Вторая проблема, связанная со справкой на основе hlp-файлов,— это то обстоятельство, что разработчики Delphi, разумеется, не сами писали эту справку, а взяли ту, которую предоставила Microsoft. Microsoft же последнюю версию справки в формате НLР выпустила в тот момент, когда уже вышла Windows 95, но еще не было Windows NT 4. Поэтому про многие функции, прекрасно работающие в NT 4, там написано, что в Windows NT они не поддерживаются, т.к. в более ранних версиях они действительно не поддерживались. В справке, поставляемой с Delphi 7 (и, возможно, с некоторыми более ранними версиями), эта информация подправлена, но даже и там отсутствуют функции, которые появились только в Windows NT 4 (как, например,
CoCreateInstanceEx
). И уж конечно, бесполезно искать в этой справке информацию о функциях, появившихся в Windows 98, 2000, XР. Соответственно, при работе в этих версиях Delphi даже не возникает вопрос, что предпочесть для получения информации о Windows API, — справку, поставляемую с Delphi, или MSDN. Безусловно, следует выбрать MSDN. Справка, поставляемая с Delphi, имеет только одно преимущество по сравнению с MSDN: ее можно вызывать из среды нажатием клавиши <F1>. Но риск получить неверные сведения слишком велик, чтобы это преимущество
могло быть серьезным аргументом. Единственная ситуация, когда предпочтительна справка, поставляемая с Delphi, — это случай, если у вас нет достаточно быстрого доступа к Интернету для работы с online-версией MSDN и нет возможности приобрести и установить его offline-версию.
Рис. 1.2. Старая (на основе hlp-файлов) справка по Windows API (показана функция
DeleteObject
)
Начиная с BDS 2006, Borland/CodeGear реализовала новую справочную систему Borland Help (рис. 1.3). По интерфейсу она очень напоминает offline версию MSDN, а также использует файлы в том же формате, поэтому технологических проблем интеграции справочных систем по Delphi и по Windows API больше не существует. В справку BDS 2006 интегрирована справка по Windows API от 2002–2003 годов (разные разделы имеют разную дату) Справка Delphi 2007 содержит сведения по Windows API от 2006 года, т.е. совсем новые. Таким образом, при работе с Delphi 2007 наконец-то можно полностью отказаться от offline-версии MSDN, а к online-версии обращаться лишь изредка, когда требуется информация о самых последних изменениях в Windows API (например, о тех, которые появились в Windows Vista).
Примечание
Несмотря на очень высокое качество разделов MSDN, относящихся к Window API, ошибки иногда бывают и там. Со временем их исправляют. Поэтому, если вы столкнулись с ситуацией, когда есть подозрение, что какая-либо функция Windows API ведёт себя не так, как это описано в вашей offline-справке, есть смысл заглянуть в online-справку — возможно, там уже появились дополнительные сведения по данной функции.
Рис. 1.3. Окно справки Delphi 2007 (функция
DeleteObject
)
Система Windows написана на C++, поэтому все описания функций Windows API, а также примеры их использования приведены на этом языке (это касается как MSDN, так и справки, поставляемой с Delphi). При этом, прежде всего, необходимо разобраться с типами данных. Большинство типов, имеющихся в Windows API. определены в Delphi. Соответствие между ними показано в табл. 1.1.
Таблица 1.1. Соответствие типов Delphi системным типам
Тип Windows API
Тип Delphi
INT
INT
UINT
LongWord
WORD
Word
SHORT
SmallInt
USHORT
Word
CHAR
Чаще всего соответствует типу
Char
, но может трактоваться также как
ShortInt
, т.к. в C++ нет разницы между символьным и целочисленным типами
UCHAR
Чаще всего соответствует типу
Byte
, но может трактоваться также как
Char
DWORD
LongWord
BYTE
Byte
WCHAR
WideChar
BOOL
LongBool
int
Integer
long
LongInt
short
SmallInt
unsigned int
Cardinal
Название типов указателей имеет префикс P или LP (Pointer или Long Pointer, в 16-разрядных версиях Windows были короткие и длинные указатели. В 32-разрядных все указатели длинные, поэтому оба префикса имеют одинаковый смысл). Например,
LPDWORD
эквивалентен типу
^DWORD
,
PUCHAR
—
^Byte
. Иногда после префикса P или LP стоит еще префикс C — он означает, что это указатель на константу. В C++ возможно объявление таких указателей, которые указывают на константное содержимое, т.е. компилятор разрешает это содержимое читать, но не модифицировать.
В Delphi такие указатели отсутствуют, и при портировании эти типы заменяются обычными указателями, т.е. префикс C игнорируется.
Типы
PVOID
и
LPVOID
соответствуют нетипизированным указателям (
Pointer
).
Для передачи символов чаще всего используется тип
TCHAR
. Windows поддерживает две кодировки: ANSI (1 байт на символ) и Unicode (2 байта на символ; о поддержке Unicode в Windows мы будем говорить далее). Тип
CHAR
соответствует символу в кодировке ANSI,
WCHAR
— Unicode. Для программ, которые используют ANSI, тип
TCHAR
эквивалентен типу CHAR, для использующих Unicode —
WCHAR
. В Delphi нет прямого аналога типу
TCHAR
. Программист сам должен следить за тем, какой символьный тип требуется в данном месте. Строки в Windows API передаются как указатели на цепочку символов, завершающихся нулем. Поэтому указатель на
TCHAR
может указывать как на единичный символ, так и на строку. Чтобы было легче разобраться, где какой указатель, в Windows API есть типы
LPTCHAR
и
LPTSTR
. Они эквивалентны друг другу, но первый принято использовать там, где требуется указатель на одиночный символ, а второй — на строку. Если строка передается в функцию только для чтения, обычно используют указатель на константу, т.е. тип
LPCTSTR
. В Delphi это соответствует PChar для ANSI и PWideChar для Unicode. Здесь следует отметить особенность записи строковых литералов в языках C/C++. Символ \ в литерале имеет специальное значение: после него идет один или несколько управляющих символов. Например, \n означает перевод строки, \t — символ табуляции и т.п. В Delphi таких последовательностей нет, поэтому при переводе примеров из MSDN следует явно писать коды соответствующих символов. Например, литерал
"а\nb"
в Delphi превращается в
'a\'#13'b'
. После символа
\
может идти число — в этом случае оно трактуется как код символа, т.е. литерал
"a\0b9"
в C/C++ эквивалентен литералу '
а'#0'b'#9
в Delphi. Если нужно, чтобы строковый литерал включал в себя сам символ \, его удваивают, т.е. литерал
"\\"
в C++ соответствует
'\'
в Delphi. Кроме того, в примерах кода, приведенных в MSDN, можно нередко увидеть, что строковые литералы обрабатываются макросами
TEXT
или
_T
, которые служат для унификации записи строковых литералов в кодировках ANSI и Unicode. При переводе такого кола на Delphi эти макросы можно просто опустить. С учетом сказанного такой, например, код (взят из примера использования Named pipes):
Большинство названий типов из левой части табл. 1.1 в целях совместимости описаны в модуле Windows, поэтому они допустимы наравне с обычными типами Delphi. Кроме этих типов общего назначения существуют еще специальные. Например, дескриптор окна имеет тип
HWND
, первый параметр сообщения — тип
WPARAM
(в старых 16-разрядных Windows он был эквивалентен типу
Word
, в 32-разрядных —
LongInt
). Эти специальные типы также описаны в модуле Windows.
Записи (
record
) в C/C++ называются структурами и объявляются с помощью слова
struct
. Из-за особенностей описания структур на языке С структуры в Windows API получают два имени: одно основное имя, составленное из главных букв, которое затем и используется, и одно вспомогательное, получающееся из основного добавлением префикса
tag
. Начиная с четвертой версии Delphi приняты следующие правила именования таких типов: простое и вспомогательное имена остаются без изменений и еще добавляется новое имя, получающееся из основного присоединением общеупотребительного в Delphi префикса
T
. Например, в функции
CreatePenIndirect
одни из параметром имеет тип
LOGPEN
. Это основное имя данного типа, а вспомогательное —
tagLOGPEN
. Соответственно, в модуле Windows определена запись
tagLOGPEN
и ее синонимы —
LOGPEN
и
TLogPen
. Эти три идентификатора в Delphi взаимозаменяемы. Вспомогательное имя встречается редко, программисты, в зависимости от личных предпочтений, выбирают либо основное имя типа, либо имя с префиксом
T
.
Описанные здесь правила именования типов могут внести некоторую путаницу при использовании VCL. Например, для описания растра в Windows API определен тип
BITMAP
(он же—
tagBITMAP
). В Delphi соответствующий тип имеет еще одно имя —
TBitmap
. Но такое же имя имеет класс
TBitmap
, описанный в модуле
Graphics
. В коде, который Delphi создает автоматически, модуль
Graphics
находится в списке
uses
после модуля
Windows
, поэтому идентификатор
TBitmap
воспринимается компилятором как
Graphics.TBitmap
, а не как
Windows.TBitmap
. Чтобы использовать
Windows.ТBitmap
, нужно явно указать имя модуля или воспользоваться одним из альтернативных имен. В более ранних версиях
Delphi
были другие правила именования типов. Например. в Delphi 2 существовал тип