Delphi 3. Библиотека программиста

       

Модуль WalkStuf


После нескольких часов «зависаний» и множества фальстартов я написал модуль, приведенный в листинге15.7. Он содержит несколько процедур общего назначения, заметно упрощающих составление списков модулей и процедур в Win95.

Листинг 15.7. Исходный текст модуля WalkStuf

{——————————————————————————————————————————————————————} { Демонстрационная программа для сбора информации } { о системе } { WALKSTUF.PAS : Служебный модуль } { Автор: Эйс Брейкпойнт, N.T.P. } { При содействии Дона Тейлора } { } { Модуль содержит процедуры для получения информации } { от модуля TlHelp32. } { } { Написано для *High Performance Delphi 3 Programming* } { Copyright (c) 1997 The Coriolis Group, Inc. } { Дата последней редакции 23/4/97 } {——————————————————————————————————————————————————————} unit WalkStuf; interface uses Windows, Classes, Dialogs, SysUtils, TLHelp32; const ws_FullPath = True; ws_NoDirectory = False; ws_Unique = True; ws_DupesOK = False; ws_InstanceCount = True; ws_NoInstanceCount = False; function GetSystemProcessList(FullPath : Boolean; Unique : Boolean) : TStringList; function GetSystemModuleList(FullPath : Boolean; Unique : Boolean; IncludeData : Boolean) : TStringList; function GetProcessModules(ProcName : String; FullPath : Boolean; IncludeData : Boolean) : TStringList; function GetLocalModuleList : TStringList; function ModuleSysInstCount (ModuleName : String) : Integer; implementation { Возвращает строку, удаляя из нее информацию о файловом пути. } function ChopPath(PathName : String) : String; var s : String; begin s := PathName; if Length(s) > 0 then begin while Pos(':', s) > 0 do Delete(s, 1, Pos(':', s)); while Pos('\', s) > 0 do Delete(s, 1, Pos('\', s)); Result := s; end else Result := '';

end; { Возвращает список строк с именами всех активных процессов в системе. } function GetSystemProcessList (FullPath : Boolean; Unique : Boolean) : TStringList; var AList : TStringList; ProcHandle : THandle; AProcEntry : TProcessEntry32; begin AList := TStringList.Create; Result := AList; AList.Sorted := True; if Unique then AList.Duplicates := dupIgnore else Alist.Duplicates := dupAccept; ProcHandle := CreateToolHelp32Snapshot (TH32CS_SNAPPROCESS, 0); if ProcHandle = -1 then Exit; AProcEntry.dwSize := sizeof(TProcessEntry32); if Process32First(ProcHandle, AProcEntry) then begin { Добавить первый процесс } if FullPath then AList.Add(AProcEntry.szExeFile) else AList.Add(ChopPath(AProcEntry.szExeFile)); { Добавить все остальные процессы } while Process32Next(ProcHandle, AProcEntry) do if FullPath then AList.Add(AProcEntry.szExeFile) else AList.Add(ChopPath(AProcEntry.szExeFile)); end; CloseHandle(ProcHandle); end; { Возвращает строковый список с именами всех активных модулей во всех процессах. } function GetSystemModuleList(FullPath : Boolean; Unique : Boolean; IncludeData : Boolean) : TStringList; var s : String; AList : TStringList; ProcHandle : THandle; ModHandle : THandle; AProcEntry : TProcessEntry32; AModEntry : TModuleEntry32; begin AList := TStringList.Create; Result := AList; AList.Sorted := True; if Unique then AList.Duplicates := dupIgnore else Alist.Duplicates := dupAccept; ProcHandle := CreateToolHelp32Snapshot (TH32CS_SNAPPROCESS, 0); if ProcHandle = -1 then Exit; AProcEntry.dwSize := sizeof(TProcessEntry32); AModEntry.dwSize := sizeof(TModuleEntry32); if Process32First(ProcHandle, AProcEntry) then begin { Обработка первого процесса } ModHandle := CreateToolHelp32Snapshot (TH32CS_SNAPMODULE, AProcEntry.th32ProcessID); if Module32First(ModHandle, AModEntry) then begin { Обработка первого модуля первого процесса } if IncludeData then s := '<' + IntToStr(AModEntry.GlblcntUsage) else s := ''; if FullPath then s := AModEntry.szExePath + s else s := AModEntry.szModule + s; AList.Add(s); { Обработка остальных модулей первого процесса} while Module32Next(ModHandle, AModEntry) do begin if IncludeData then s := '<' + IntToStr(AModEntry.GlblcntUsage) else s := ''; if FullPath then s := AModEntry.szExePath + s else s := AModEntry.szModule + s; AList.Add(s); end; CloseHandle(ModHandle); { Обработка оставшихся процессов } while Process32Next(ProcHandle, AProcEntry) do begin ModHandle := CreateToolHelp32Snapshot(TH32CS_SNAPMODULE, AProcEntry.th32ProcessID); if Module32First(ModHandle, AModEntry) then begin { Обработка первого модуля текущего процесса } if IncludeData then s := '<' + IntToStr(AModEntry.GlblcntUsage) else s := ''; if FullPath then s := AModEntry.szExePath + s else s := AModEntry.szModule + s; AList.Add(s); { Обработка оставшихся модулей текущего процесса } while Module32Next(ModHandle, AModEntry) do begin if IncludeData then s := '<' + IntToStr(AModEntry.GlblcntUsage) else s := ''; if FullPath then s := AModEntry.szExePath + s else s := AModEntry.szModule + s; AList.Add(s); end; end; CloseHandle(ModHandle); end; { while } end; end; CloseHandle(ProcHandle); end; { Возвращает строковый список с именами всех активных модулей текущего процесса. } function GetLocalModuleList : TStringList; var AList : TStringList; ModHandle : THandle; AModEntry : TModuleEntry32; begin AList := TStringList.Create; AList.Sorted := True; Result := AList; ModHandle := CreateToolHelp32Snapshot (TH32CS_SNAPMODULE, 0); if ModHandle = -1 then Exit; AModEntry.dwSize := sizeof(TModuleEntry32); if Module32First(ModHandle, AModEntry) then begin { Добавляем первый модуль } AList.Add(AModEntry.szModule); { Добавляем остальные модули } while Module32Next(ModHandle, AModEntry) do AList.Add(AModEntry.szModule); end; CloseHandle(ModHandle); end; { Возвращает список строк с именами всех активных модулей процесса с заданным именем. } function GetProcessModules(ProcName : String; FullPath : Boolean; IncludeData : Boolean) : TStringList; var s : String; Found : Boolean; Done : Boolean; AList : TStringList; ProcHandle : THandle; ModHandle : THandle; AProcEntry : TProcessEntry32; AModEntry : TModuleEntry32; begin AList := TStringList.Create; Result := AList; AList.Sorted := True; ProcHandle := CreateToolHelp32Snapshot (TH32CS_SNAPALL, 0); if ProcHandle = -1 then Exit; AProcEntry.dwSize := sizeof(TProcessEntry32); AModEntry.dwSize := sizeof(TModuleEntry32); if Process32First(ProcHandle, AProcEntry) then begin { Просматриваем процессы, пока не будет найдено совпадение } Found := UpperCase(AProcEntry.szExeFile) = UpperCase(ProcName); if not Found then repeat Done := not Process32Next(ProcHandle, AProcEntry); if not Done then Found := UpperCase(AProcEntry.szExeFile) = UpperCase(ProcName); until Done or Found; if Found then begin ModHandle := CreateToolHelp32Snapshot(TH32CS_SNAPMODULE, AProcEntry.th32ProcessID); if Module32First(ModHandle, AModEntry) then begin { Обработка первого модуля первого процесса } if IncludeData then s := '<' + IntToStr(AModEntry.GlblcntUsage) else s := ''; if FullPath then s := AModEntry.szExePath + s else s := AModEntry.szModule + s; AList.Add(s); { Обработка остальных модулей первого процесса } while Module32Next(ModHandle, AModEntry) do begin if IncludeData then s := '<' + IntToStr(AModEntry.GlblcntUsage) else s := ''; if FullPath then s := AModEntry.szExePath + s else s := AModEntry.szModule + s; AList.Add(s); end; end; CloseHandle(ModHandle); end; end; CloseHandle(ProcHandle); end; { Возвращает количество экземпляров заданного модуля во всех процессах системы. } function ModuleSysInstCount(ModuleName : String) : Integer; var Idx : Integer; p : Integer; s : String; ModList : TStringList; MatchFound : Boolean; begin Result := -1; ModList := GetSystemModuleList(ws_NoDirectory, ws_DupesOK, ws_InstanceCount); if ModList = nil then Exit; Idx := 0; p := 0; MatchFound := False; while (Idx < ModList.Count) and not MatchFound do begin s := ModList.Strings[Idx]; p := pos('<', s); MatchFound := Uppercase(copy(s, 1, p - 1)) = Uppercase(ModuleName); if not MatchFound then Inc(Idx); end; { while } if MatchFound then Result := StrToInt(copy(s, p + 1, Length(s) - p)) else Result := 0; end; end.

Модуль WalkStuf содержит пять полезных функций, заметно облегчающих дальнейшие исследования. GetSystemProcessList возвращает список строк с именами всех активных процессов в системе. Предусмотрена возможность вывода только имени процесса (без полного пути) и подавления множественных экземпляров одного процесса. GetSystemModuleList возвращает список строк с именами всех модулей во всех процессах. Предусмотрены аналогичные возможности для подавления информации о пути и множественных экземпля рах; кроме того, в каждую строку можно дополнительно включить количество экземпляров каждого модуля, существующих в системе. GetProcessModules возвращает список строк с именами всех модулей заданного процесса. GetLocal ModuleList создает список модулей, принадлежащих только заданному процессу. Наконец, ModuleSystemCount возвращает целое число, равное количеству экземпляров заданного модуля в системе.

Кое-что в функциях модуля WalkStuf заслуживает особых пояснений. GetSystemProcessList показывает, как происходит перебор процессов из списка. Переменной ProcHandle присваивается логический номер области внутри KERNEL32, подготовленной для хранения списка всех процессов. Затем полю dwSize записи TProcessEntry32 (предназначенной для хранения информации о процессе) присваивается размер этого типа данных (на первый взгляд это кажется почти глупым, но на самом деле критически важно для правильной работы!). Затем вызывается Process32First с параметрами ProcHandle (информация из KERNEL32) и AProcEntry (это переменная для хранения данных).

Если Process32First возвращает True, значит, информация о первом процессе из списка была скопирована в поля AProcEntry. Вероятно, наибольший интерес представляют поля szExeFile и th32ProcessID. Первое содержит строку с полным путем к EXE-файлу, создавшему процесс. Второе содержит уникальный идентификатор изучаемого процесса, который можно передавать другим функциям ToolHelp. Вскоре об этом будет рассказано подробнее.

После того как szExeFile попадет в список строк, цикл while используется для многократных вызовов Process32Next. Эта функция вызывается с теми же параметрами, и если она возвращает True, значит, в AProcEntry были помещены данные следующего процесса (если вам приходилось пользоваться функциями FindFirst и FindNext под DOS, эта механика покажется знакомой). Когда перебор закончен, остается лишь выполнить последнюю задачу. Ведь вызов CreateToolHelp32Snapshot создал объект Win95, который необходимо уничтожить. Это делается с помощью вызова CloseHandle.

GetSystemModule представляет собой более сложный вариант перебора. Полный список модулей каждого процесса просматривается функциями Module32 First и Module32Next. Для каждого процесса CreateToolHelp32Snapshot возвращает логический номер. На этот раз при вызове используется уникальный идентификатор текущего изучаемого процесса (AProcEntry.th32ProcessID), благода ря чему полученный логический номер относится к информации о модулях, принадлежащих только указанному процессу. Обратите внимание на использование маски TH32CS_SNAPMODULE, которая ограничивает полученную информа цию сведениями о модулях.

Записи TModuleEntry32 содержат несколько полей. Для наших целей наиболь ший интерес представляют поля szExePath (строка, содержащая полный путь к модулю), szModule (строка с базовым именем модуля) и GlblcntUsage (двойное слово, содержащее количество экземпляров данного модуля в системе).

Снова обратите внимание на то, что в поле dwSize записи AModEntry необходимо указать размер записи TModuleEntry32, и что для каждого вызова CreateTool Help32Snapshot должен присутствовать парный вызов CloseHandle, уничтожаю щий созданный объект.

Все остальные функции в основном являются «вариациями на тему». Get LocalModuleList перебирает модули, принадлежащие только текущему процессу, для чего в качестве идентификатора процесса передается 0. GetProcessModules перебирает список модулей и ищет в нем заданный процесс. Если поиск окажется успешным, функция перебирает модули этого процесса. Наконец, Module SysInstCount с помощью вызова GetSystemModuleList получает список модулей для всей системы, из которого отбирает заданный модуль. Из строки, соответству ющей найденному модулю, она выбирает количество экземпляров и возвращает его в виде целого числа.



Содержание раздела