А. Григорьев - О чём не пишут в книгах по Delphi
- Название:О чём не пишут в книгах по Delphi
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2008
- Город:СПб
- ISBN:978-5-9775-019003
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание
Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.
Для программистов
О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
В очереди могут находиться сообщения и для того приложения, которое выполняет блокирующий вызов. В этом случае будет снова вызвана оконная процедура, инициировавшая блокирующую операцию. Это напоминает рекурсию, при которой процедура вызывает сама себя: в памяти компьютера будут одновременно две активации этой процедуры. Упрощенно это выглядит так: оконная процедура вызывает блокирующую функцию (например, accept), а та, в свою очередь, снова вызывает ту же самую оконную процедуру. При этом вторая активация не может выполнять никаких операций с сокетами: они будут завершены с ошибкой WSAEINPROGRESS
. Эта ошибка не фатальная, она указывает, что в данный момент выполняется блокирующая операция, и программа должна подождать ее завершения и лишь потом пытаться работать с сокетами (т.е. не раньше, чем первая активация оконной процедуры вновь получит управление). Существует специальная функция WSAIsBlocking
, которая возвращает True
, если в данный момент выполняется блокирующая операция и работа с сокетами невозможна.
Вторая активация процедуры может прервать блокирующий вызов с помощью функции WSACancelBlockingСаll
. При этом первая активация получит ошибку WSAECANCELLED
.
Программа может устанавливать свою процедуру, которая будет вызываться во время выполнения блокирующей операции. Для этого предусмотрены функции WSASetBlockingHook
и WSAUnhookBlockingHook
.
Данная модель неудобна, поэтому разработчики WinSock 1 рекомендуют модель асинхронных сокетов, более приспособленную к особенностям Windows.
В 32-разрядных версиях WinSock такая модель работы поддерживается в полном объеме, за исключением того, что по умолчанию при блокирующем вызове не вызывается никакая функция. Поэтому если не вызове не вызывается никакая функция. Поэтому если не использовать WSASetBlockingHook
, то в 32-разрядном приложении невозможно получить ситуацию, когда операция с сокетом не будет выполнена из-за того, что в этот момент уже выполняется другая операция, и второй активации оконной процедуры из-за блокирующего вызова тоже не будет создано. Отметим, что разные нити могут одновременно выполнять блокирующие операции с сокетами, и это не приведет к появлению ошибки WSAEINPROGRESS
.
Все перечисленные функции формально исключены из спецификации WinSock 2, хотя фактически они присутствуют в библиотеке WS2_32.dll и при необходимости могут быть задействованы (это, правда, осложняется тем, что в новых версиях MSDN отсутствует их описание). Тем не менее причин ориентироваться на эту неудобную модель в 32-разрядных версиях Windows, видимо, нет. Описание этих функций мы здесь привели только для того, чтобы упоминания об ошибках WSAEINPROGRESS
и WSAECANCELLED
, которые иногда встречаются в MSDN, не смущали вас.
2.2.3. Информация о протоколе
Ранее мы уже видели, что передача данных через сокет осуществляется одними и теми же функциями независимо от протокола. Но при этом программа должна учитывать, является ли протокол потоковым, дейтаграммным или иным. Кроме того, информация о протоколе требуется для создания сокета и для распределения ролей между клиентом и сервером при установлении соединения. Чтобы работать с любым протоколом, программа должна иметь возможность получить всю эту информацию и выполнить на основе ее те или иные действия. Могут также понадобиться такие сведения, как максимальное число сокетов, поддерживаемых провайдером протокола, допустимый диапазон адресов, максимальный размер сообщений для дейтаграммных протоколов и т.д. Для хранения полного описания протокола и его провайдера в WinSock 2 предусмотрена структура WSAPROTOCOL_INFO
. Она не описана в модуле WinSock, т.к. в WinSock 1 ее нет. Тем, кто захочет использовать эту структуру, придется самостоятельно добавлять ее описание в программу. Листинг 2.36 показывает, как выглядит эта структура.
WSAPROTOCOL_INFO
// ***** Описание на C++ *****
typedef struct _WSAPROTOCOLCHAIN {
int ChainLen;
DWORD ChainEntries[MAX_PROTOCOL_CHAIN];
} WSAPROTOCOLCHAIN, *LPWSAPROTOCOLCHAIN;
typedef struct _WSAPROTOCOL_INFO {
DWORD dwServiceFlags1;
DWORD dwServiceFlags2;
DWORD dwServiceFlags3;
DWORD dwServiceFlgs4;
DWORD dwProviderFlags;
GUID ProviderId;
DWORD dwCatalogEntryId;
WSAPROTOCOLCHAIN ProtocolChain;
int iVersion;
int iAddressFamily;
int iMaxSockAddr;
int iMinSockAddr;
int iSocketType;
int iProtocol;
int iProtocolMaxOffset;
int iNetworkByteOrder;
int iSecurityScheme;
DWORD dwMessageSize;
DWORD dwProviderReserved;
TCHAR szProtocol[WSAPROTOCOL_LEN - 1];
} WSAPROTOCOL_INFO, *LPWSAPROTOCOL_INFO;
// ***** Описание на Delphi *****
TWSAProtocolChain = packed record
ChainLen: Integer;
ChainEntries: array[0..MAX_PROTOCOL_CHAIN - 1] of DWORD;
end;
//Структура на C++ содержит тип TCHAR, который, как мы
// говорили в главе 1, может означать как Char,
// так и WideChar, т.е. структура должна иметь
// два варианта описания: TWSAProtocolInfoA для
// однобайтной кодировки и TWSAProtocolInfo для
// двухбайтной. Соответственно, все функции
// использующие эту структуру, реализованы
// в системных библиотеках в двух вариантах.
// Здесь мы приводим только ANSI-вариант.
PWSAProtocolInfo = ^TWSAProtocolInfo;
TWSAProtocolInfo = packed record
dwServiceFlags1: DWORD;
dwServiceFlags2: DWORD;
dwServicsFlags3: DWORD;
dwServiceFlags4: DWORD;
dwProviderFlags: DWORD;
ProviderId: GUID;
dwCatalogEntryId: DWORD;
ProtocolChain: TWSAProtocolChain;
iVersion: Integer;
iAddressFamily: Integer;
iMaxSockAddr: Integer;
iMinSockAddr: Integer;
iSocketType: Integer;
iProtocol: Integer;
iProtocolMaxOffset: Integer;
iNetworkByteOrder: Integer;
iSecurityScheme: Integer;
dwMessageSize: DWORD;
dwProviderReserved: DWORD;
szProtocol: array [0..WSAPROTOCOL_LEN] of Char;
end;
Расшифровка полей типа TWSAProtocolInfo
есть в MSDN, мы здесь не будем ее приводить.
Сама функция WSAEnumProtocols
, которая позволяет получить список всех протоколов, провайдеры которых установлены на компьютере, приведена в листинге 2.37.
WSAEnumProtocols
// ***** описание на C++ *****
int WSAEnumProtocols(LPINT lpiProtocols, LPWSAPROTOCOL_INFO lpProtocolBuffer, LPDWORD lpdwBufferLength);
// ***** Описание на Delphi *****
function WSAEnumProtocols(lpiProtocols: PInteger; lpProtocolBuffer: PWSAProtocolInfo; var BufferLength: DWORD): Integer;
В старых версиях MSDN в описании этой функции есть небольшая опечатка: тип параметра lpdwBufferLength
назван LLPDWORD
вместо LPDWORD
.
Библиотека WS2_32.dll придерживается тех же правил насчет ANSI- и Unicode-вариантов функций, что и другие системные библиотеки (см. разд. 1.1.12), поэтому в ней нет функции с именем WSAEnumProtocols
, а есть WSAEnumProtocolsA
и WSAEnumProtocolsW
. Эти функции работают с разными вариантами структуры WSAPROTOCOL_INFO
, которые различаются типом элементов в последнем массиве — CHAR
или WCHAR
.
Интервал:
Закладка: