Все структуры в Windows API описаны безpacked
, запрещающее выравнивание.
При описании структур Windows API можно иногда встретить ключевое слово union
(см., например, структуру in_addr
). Объединение нескольких полей с помощью этого слова означает, что все они будут размещены по одному адресу. В Delphi это соответствует вариантным записям (т. е. использованию сазе в record). Объединения в C/C++ гибче, чем вариантные записи Delphi, т. к. позволяют размещать вариантную часть в любом месте структуры, а не только в конце. При переносе таких структур в Delphi иногда приходится вводить дополнительные типы.
Теперь рассмотрим синтаксис описания самой функции в C++ (листинг 1.1).
<Тип функции> <Имя функции> ' ('
[<Тип параметра> {<Имя параметра>}
(',' <Тип параметра> {<Имя параметра>} }
]
')';
Как видно из листинга 1.1, при объявлении функции существует возможность указывать только типы параметров и не указывать их имена. Однако это считается устаревшим и применяется крайне редко (если не считать "параметров" типа VOID
, о которых написано далее).
Необходимо помнить, что в C/C++ различаются верхний и нижний регистры, поэтому HDC
, hdc
, hDC
и т. д. — это разные идентификаторы (автор С очень любил краткость и хотел, чтобы можно было делать не 26, а 52 переменные с именем из одной буквы). Поэтому часто можно встретить, что имя параметра и его тип совпадают с точностью до регистра. К счастью, при описании функции в Delphi мы не обязаны сохранять имена параметров, значение имеют лишь их типы и порядок следования. С учетом всего этого функция, описанная в справке как
HMETAFILE CopyMetaFile(HMETAFILE hmfSrc, LPCTSTR lpszFile);
в Delphi имеет вид
function СоруМеtaFile(hnfSrc: HMETAFILE; lpszFile: LPCTSTR): HMETAFILE;
или, что то же самое.
function CopyMetaFile(hnfSrc: HMETAFILE; lpszFile: PChar): HMETAFILE;
Компилятор Delphi допускает, чтобы имя параметра процедуры или функции совпадало с именем типа, поэтому мы в дальнейшем увидим, что иногда имя параметра и его тип совпадают, только записываются в разном регистре, чтобы прототип функции на Delphi максимально соответствовал исходному прототипу на C/C++. При этом следует учитывать что соответствующий идентификатор внутри функции будет рассматриваться как имя переменной, а не типа, поэтому, например, объявлять локальную переменную данного типа придется с явным указанием имени модуля, в котором данный тип объявлен.
Несколько особняком стоит тип VOID
(или void
, что то же самое, но в Windows API этот идентификатор встречается существенно реже). Если функции имеет такой тип, то в Паскале она описывается как процедура. Если вместо параметров у функции в скобках указан void
, это означает, что функция не имеет параметров. Например, функция
VOID CloseLogFile(VOID);
в Delphi описывается как
procedure CloseLogFile;
Язык C++, в отличие от С, допускает объявление функций без параметров, т. е. функцию CloseLogFile
можно было бы объявить так: VOID CloseLogFile();
В C++ эти варианты объявления эквивалентны, но в Windows API варианту явного параметра встречается существенно реже из-за несовместимости с C.
Когда тип параметра является указателем на другой тип (обычно начинается с букв LP), при описании этой функции в Delphi можно пользоваться параметром-переменной, т. к. в этом случае функции передается указатель. Например, функция
int GetRgnBox(HRGN hrgn, LPRECT lprc);
в модуле Windows описана как