Что касается самих результатов, то они, конечно, сильно зависят от конфигурации компьютера. По первым двум тестам время выполнения для DDB-растра может быть как в два-три раза меньше, чем для DIB, так и несколько превышать его. В третьем тесте DIB-растр, разумеется, существенно опережает по скорости DDB, хотя отношение и здесь зависит от компьютера. Также наблюдается некоторая зависимость от версии Delphi, под которой откомпилирован проект. Например, первый тест и для DIB, и для DDB выполняется несколько быстрее под Delphi 2007, чем под Delphi 5, а вот третий тест под Delphi 2007 выполняется несколько медленнее.
1.3. Обобщающие примеры
Рассмотрев основы работы с функциями API. мы переходим к обобщающим примерам — программам, использующим разные средства API
для создания простого законченного примера.
1.3.1. Обобщающий пример 1 — Информация о процессах
Первым обобщающим примером станет программа для получения информации о процессах системы и об окнах, которые они открывают. На компакт-диске, прилагаемом к книге, эта программа называется ProcInfo. Окно программы ProcInfo показано на рис 1.13.
Рис. 1.13. Окно программы ProcInfo
1.3.1.1. Получение списка процессов
Исторически сложилось так, что существует два способа получить список процессов: с помощью функций Tool Help и посредством функций PSAPI. Эти две группы функций использовались в разных линиях Windows: функции Tool Help появились в Windows 95, функции PSAPI — в Windows NT 4. Windows 2000 XP также поддерживают функции Tool Help, в то время как Windows 98/ME не поддерживают PSAPI. Поэтому мы выберем функции Tool Help, что даст нашему примеру возможность работать во всех версиях Windows, кроме NT 4 (впрочем, в Windows 95 пример тоже не будет работать, но по другой причине: из-за функций
GetWindowInfo
и
RealGetWindowClass
, отсутствующих в этой версии). Функции Tool Help объявлены в модуле
TlHelp32
.
Для получения списка процессов необходимо сделать "снимок" состояния системы с помощью функции
CreateToolhelp32Snapshot
. Эта функция создает специальный объект, который может хранить информацию о процессах, модулях, нитях и кучах, созданных в системе. Этот объект называется снимком потому, что информация, хранящаяся в нем, актуальна на момент вызова функции
CreateToolhelp32Snapshot
; дальнейшие изменения списка процессов, модулей и т.п. не приводят к изменению снимка. Доступ к снимку, как и к большинству объектов системы, осуществляется через его дескриптор. В данном случае функция
CreateToolhelp32Snapshot
вызывается с параметром
TH32CS_SNAPPROCESS
для получения списка процессов.
Навигация по списку процессов, сохраненных в снимке, осуществляется с помощью функций
Process32First
и
Process32Next
. Они позволяют получить ряд параметров процесса, главный среди которых — идентификатор процесса (Process Identifier, PID). Это уникальный идентификатор процесса, с помощью которого можно отличать один процесс от другого.
Примечание
Не следует путать идентификатор процесса и дескриптор объекта процесса, который используется, например, в функции
SetPriorityClass
. Объект процесса — это специальный объект, связанный с процессом, но не тождественный ему. В частности, объект процесса может продолжать существовать уже после того, как сам процесс завершит работу (это позволяет, например, корректно синхронизироваться с уже завершенным процессом при помощи функции
WaitForSingleObject
). Через объект процесса можно управлять многими свойствами процесса. Поучить дескриптор объекта процесса по идентификатору процесса можно с помощью функции
OpenProcess
.
Код для получения списка процессов показан в листинге 1.42.
Листинг 1.42. Получение списка процессов с помощью Tool Help
procedure TProcessesInfoForm.FillProcessList;
var
SnapProc: THandle;
ProcEntry: TProcessEntry32;
Item: TListItem;
begin
ClearAll;
//
Создаем снимок, в котором сохраняем все процессы, а
// затем в цикле получаем информацию о каждом из этих
// Pointer, а PID - это целое число, но т.к. оба этих
// типа 32-битные, их можно приводить друг к другу
Item.Data := Pointer(ProcEntry.th32ProcessID);
until not Process32Next(SnapProc, ProcEntry);
finally
CloseHandle(SnapProc);
end
else
begin
ListProcesses.Visible := False;
LabelProcessError.Caption :=
'Невозможно получить список процессов:'#13#10'Ошибка №' +
IntToStr(GetLastError);
end;
end;
Для получения списка модулей данного процесса также используется снимок. Функция
CreateToolhelp32Snapshot
вызывается с параметром
TH32CS_SNAPMODULE
, в качестве второго параметра ей передается PID процесса, модули которого требуется получить. Навигация по снимку модулей осуществляется с помощью функций
Module32First
и
Module32Next
. В остальном код получения списка модулей совпадает с кодом, приведенным в листинге 1.42.
1.3.1.2. Получение списка и свойств окон
Список окон, созданных процессом, формируется с помощью функции
EnumWindows
, которая позволяет получить список всех окон верхнего уровня (т.е. расположенных непосредственно на рабочем столе). Для каждого из этих окон с помощью функции
GetWindowThreadProcessID
определяется идентификатор процесса. Окна, не принадлежащие выбранному процессу, отсеиваются.
Для каждого из окон верхнего уровня, принадлежащих процессу, с помощью функции
EnumChildWindows
ищутся дочерние окна, а для каждого из найденных таким образом дочерних окон — его дочерние окна. Здесь следует учесть, что
EnumChildWindows
возвращает не только дочерние окна заданного окна, но и все окна, которыми владеют эти дочерние окна. Чтобы в дереве окон не было дублирования, при построении очередного уровня дерева окон отбрасываются все окна, непосредственным родителем которых не является данное окно. Код, выполняющий построение дерева, приведен в листинге 1.43.