Чтение онлайн

на главную

Жанры

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

Во втором варианте функции передается указатель, хранящийся в переменной

S
. Такое приведение
string
к
PChar
безопасно, т.к. строка, на которую ссылается переменная
S
, не будет модифицироваться. Но здесь существует одна тонкость: конструкция
PChar(S)
— это не просто приведение типов, при ее использовании неявно вызывается функция
_LStrToPChar
. Как мы уже говорили, когда
string
хранит пустую строку, указатель просто имеет
значение
nil. Функция
_LStrToPChar
проверяет, пустая ли строка хранится в переменной, и, если не пустая, возвращает этот указатель, а
если пустая, то возвращает не
nil
, а указатель на символ
#0
, который специально для этого размещен в сегменте кода. Поэтому даже если содержит пустую строку, в функцию будет передан ненулевой указатель.

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

string
. Но его можно привести к
PChar
. Память для хранения результата выражения выделяется динамически, как и для обычных переменных типа string. Чтобы передать указатель на но выражение в функцию, следует привести его к
PChar
. В эпилог процедуры, вызывающей функцию
SetWindowText
или иную функцию с подобным аргументом, добавляется код, который освобождает динамически сформированную строку, поэтому утечек памяти не происходит. Разумеется, существуют и другие способы формирования параметра типа
LPCTSTR
, кроме предложенных здесь. Можно, например, выделить память для нуль-терминированной строки с помощью
StrNew
или родственной ей функции из модуля
SysUtils
. Можно использовать массив типа
Char
. Можно выделять память какими-либо другими способами. Но предложенные здесь три варианта в большинстве случаев наиболее удобны.

Параметры типа

LPTSTR
применяются в тех случаях, когда функция может не только читать, но и модифицировать передаваемое ей значение. В большинстве случаев такие параметры чисто выходные, т.е. функция не интересуется, какое значение имел параметр при вызове, используя его только для возврата значения. При возврате строкового значения всегда возникает проблема: где, кем и как будет выделена память, в которую будет записана строка? Функции Windows API, за очень редким исключением, решают эту проблему следующим образом: память должна выделить вызывающая программа, а в функцию передается указатель на этот заранее выделенный блок. Сама функция только копирует строку в этот блок.

Таким образом, перед программой встает задача узнать, какой объем памяти следует выделить под возвращаемую строку. Здесь API не предлагает универсального решения, разные функции по-разному решают эту проблему. Например, при получении заголовка окна с помощью

GetWindowText
размер этого заголовка можно узнать, вызвав предварительно
GetWindowTextLength
. Функции типа
GetCurrentDirectory
возвращают длину строки. Если при первом вызове этой функции памяти выделено недостаточно, можно увеличить буфер и вызвать функцию еще раз. И наконец, есть функции типа
SHGetSpecialFolderPath
, в описании которых написано, каков минимальный размер буфера, необходимый для гарантированной передачи полной строки этой функцией (это, разумеется, возможно только в том случае, когда размер возвращаемой строки имеет какое-то естественное ограничение). Следует также отметить, что большинство API-функций, возвращающих строки, в качестве одного из параметров принимают размер буфера, чтобы не скопировать больше байтов, чем буфер может принять.

Выделять буфер для получения строки можно многими способами. На практике удобнее всего статические массивы, тип

string
или динамическое выделение памяти для нуль-терминированных строк.

Статические массивы могут использоваться, если размер буфера известен на этапе компиляции. Массивы типа

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

Строки типа

string
также могут служить буфером для получения строковых значений от системы. Для этого нужно предварительно установить требуемую длину строки с помощью
SetLength
, а затем передать указатель на начало строки в функцию API. Здесь следует соблюдать осторожность: если длина строки окажется равной нулю, переменная типа
string
будет иметь значение
nil
, а система попытается записать по этому указателю пустую строку, состоящую из единственного символа
#0
. Это приведет к ошибке Access violation.

Третий способ — выделение памяти для буфера с помощью

StrAlloc
или аналогичной ей функции. Память, выделенную таким образом, следует обязательно освобождать с помощью
StrDispose
. При этом крайне желательно использовать конструкцию
try/finally
, чтобы возникновение исключений не привело к утечкам памяти.

Все три способа получения строковых данных от функций Windows API показаны в примере

EnumWnd
, находящемся на прилагаемом компакт-диске.

1.2. Примеры использования Windows API

В этом разделе разобраны простые примеры, находящиеся на компакт-диске. Все эти примеры уже упоминались ранее, и каждый из них иллюстрирует какую-то отдельно взятую возможность API. Более сложным обобщающим примерам, которые задействуют сразу несколько возможностей API и VCL, посвящен следующий, третий раздел данной главы.

1.2.1. Пример EnumWnd

Программа EnumWnd представляет собой простой пример использования функций

EnumWindows
и
EnumChildWindows
, а также функций обратного вызова, которые необходимы для работы этих двух функций. Программа ищет все окна, созданные на данный момент в системе, и отображает их в виде дерева: каждый узел дерева соответствует одному окну, дочерние узлы соответствуют дочерним окнам данного окна (рис. 1.8).

Программа EnumWnd является также примером того, как можно работать с параметрами типа LPTSTR, через которые функции Windows API возвращают программе строковые значения. В разд. 1.1.13 были перечислены три способа создания буфера для работы с такими параметрами: выделение памяти в стеке в виде массива элементов типа

Char
, использование строк типа
string
и строк типа
PChar
. Все три способа реализованы в примере
EnumWnd
. На главной и единственной форме программы
EnumWnd
размещены два компонента:
TreeWindow
типа
TTreeView
и кнопка
BtnBuild
. Обработчик нажатия кнопки выглядит очень лаконично (листинг 1.21).

Листинг 1.21. Обработчик нажатия кнопки
BtnBuild

procedure TFomWindows.BtnBuildClick(Sender: TObject);

begin

 Screen.Cursor := crHourGlass;

 try

TreeWindows.Items.Clear;

EnumWindows(@EnumWindowsProc, 0);

 finally

Screen.Cursor := crDefault;

 end;

end;

Рис. 1.8. Окно программы EnumWnd

Поделиться:
Популярные книги

Ученичество. Книга 1

Понарошку Евгений
1. Государственный маг
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Ученичество. Книга 1

Идеальный мир для Лекаря 7

Сапфир Олег
7. Лекарь
Фантастика:
юмористическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 7

Обыкновенные ведьмы средней полосы

Шах Ольга
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Обыкновенные ведьмы средней полосы

Треск штанов

Ланцов Михаил Алексеевич
6. Сын Петра
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Треск штанов

Медиум

Злобин Михаил
1. О чем молчат могилы
Фантастика:
фэнтези
7.90
рейтинг книги
Медиум

"Фантастика 2023-123". Компиляция. Книги 1-25

Харников Александр Петрович
Фантастика 2023. Компиляция
Фантастика:
боевая фантастика
альтернативная история
5.00
рейтинг книги
Фантастика 2023-123. Компиляция. Книги 1-25

Гром над Тверью

Машуков Тимур
1. Гром над миром
Фантастика:
боевая фантастика
5.89
рейтинг книги
Гром над Тверью

Идеальный мир для Лекаря 11

Сапфир Олег
11. Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 11

Совок

Агарев Вадим
1. Совок
Фантастика:
фэнтези
детективная фантастика
попаданцы
8.13
рейтинг книги
Совок

Табу на вожделение. Мечта профессора

Сладкова Людмила Викторовна
4. Яд первой любви
Любовные романы:
современные любовные романы
5.58
рейтинг книги
Табу на вожделение. Мечта профессора

Сонный лекарь 4

Голд Джон
4. Не вывожу
Фантастика:
альтернативная история
аниме
5.00
рейтинг книги
Сонный лекарь 4

Огненный князь 4

Машуков Тимур
4. Багряный восход
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Огненный князь 4

Войны Наследников

Тарс Элиан
9. Десять Принцев Российской Империи
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Войны Наследников

Бестужев. Служба Государевой Безопасности. Книга вторая

Измайлов Сергей
2. Граф Бестужев
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Бестужев. Служба Государевой Безопасности. Книга вторая