Монитор процессов, потоков и окон
Цель работы: знакомство с функциями Win32, обеспечивающими получение информации о выполняющихся в данный момент процессах MS Windows 9x, Me, 2000 и используемых ими окнах.
Первый этап получения информации о выполняющихся в системе процессах - получение снимка (snapshot) системы, который содержит информацию о состоянии системы в момент выполнения снимка. Снимок создается с помощью функции CreateToolHelp32Snapshot (dwFlags, th32ProcessID), первый аргумент определяет, какая информация будет записана в снимок- возможные значения приведены в таблице.
Флаг | Описание |
TH32CS_SnapHEAPLIST | В снимок включается список куч, принадлежащих указанному процессу |
TH32CS_SnapPROCESS | В снимок включается список процессов, присутствующих в системе |
TH32CS_SnapTHREAD | В снимок включается список потоков |
TH32CS_SnapMODULE | В снимок включается список модулей, принадлежащих указанному процессу |
TH32CS_SnapALL | В снимок включается список куч, процессов, потоков и модулей |
Второй аргумент определяет процесс, информация о котором необходима (если требуется список куч и модулей). В остальных случаях он игнорируется.
Второй этап - извлечение из снимка списка процессов. Для выполнения этой операции служат функции:
Process32First ( hSnapshot, LPProcessEntry32)
Process32Next ( hSnapshot, LPProcessEntry32).
Первый аргумент - хэндл созданного снимка (возвращает функция CreateToolHelp32Snapshot).
Второй аргумент- структура, содержащая 10 полей.
Первое поле этой структуры - dwSize - должно перед вызовом функции содержать размер структуры в байтах - sizeof (ProcessEntry32).
Второе поле - cntUsage - содержит число ссылок на процесс, то есть число потоков, которые в настоящий момент используют какие-либо данные процесса.
Третье поле - th32ProcessID - является идентификатором процесса.
Шестое поле -cntThreads - определяет число потоков, принадлежащих процессу.
Седьмое поле - th32ParentProcessID - является идентификатором родительского по отношению к текущему процесса.
Поле pcPriClassBase cодержит базовый приоритет процесса.
Поле szExeFile[MAX_PATH] cодержит полное имя файла, создавшего процесс. Значение MAX_PATH равно 260.
Для того, чтобы получить информацию о первом процессе в снимке, необходимо вызвать функцию Process32First. В случае успешного завершения функция возвращает TRUE. Для того, чтобы просмотреть все оставшиеся процессы, нужно вызывать функцию Process32Next до тех пор, пока она не возвратит FALSE.
В список используемых модулей - uses - необходимо добавить модуль TlHelp32
ПРИМЕР использования рассмотренных выше функций.
var
SH : Cardinal;
Num, I : Integer;
PPE : TProcessEntry32;
Full_Path, Exe_name: array [0..40]of string;
ProcessID : array [0..40] of integer;
begin
Num := 0;
SH := CreateToolHelp32SnapShot(Th32cs_SnapAll, 0);
Process32First(SH, PPE);
Full_Path[Num] := PPE.szExeFile;
Exe_Name[Num] := ExtractFileName(Full_Path[Num]);
ProcessID[Num] := PPE.Th32ProcessID;
Num := Num + 1;
// получение информации о других процессах
while Process32Next(SH, PPE) do
begin
Full_Path[Num] := PPE.szExeFile;
Exe_Name[Num] := ExtractFileName(Full_Path[Num]);
ProcessID[Num] := PPE.Th32ProcessID;
Num := Num + 1;
end;
Listbox1.Clear; // вывод списка полных путей выполняющихся процессов
for I := 0 to Num-1 do Listbox1.Items.Add(Full_path[i]);
CloseHandle(SH)
end;
Третий этап - извлечение из снимка списка потоков. Для выполнения этой операции служат функции
Thread32First ( hSnapshot, LPTHREADEntry32)
Thtead32Next ( hSnapshot, LPTHREADEntry32).
Первый аргумент - хэндл созданного снимка (возвращает функция CreateToolHelp32Snapshot).
Второй аргумент- структура, содержащая 7 полей.
Первое поле этой структуры - dwSize - должно перед вызовом функции содержать размер структуры в байтах - sizeof (THREADEntry32).
Поле th32OwnerProcessID содержит идентификатор родительского процесса.
Поле tpBasePri содержит текущий приоритет потока.
Поле tpDeltaPri содержит разность между текущим уровнем приоритета потока и базовым уровнем, то есть тем, который присваивается при создании потока.
Пример использования рассмотренных функций:
var
Shand : Cardinal;
ppe : tagPROCESSENTRY32;
ppeTh : tagTHREADENTRY32;
name : string;
ch: char;
pri,cnt,ii : integer;
prId: Dword;
begin
Shand := CreateToolHelp32Snapshot (TH32CS_SNAPALL,0);
Thread32First (shand,ppeTh);
listbox2.Clear;
repeat
name:='';
pri:= ppeTh.tpBasePri;
cnt:= ppeTh.tpDeltaPri;
prId:=ppeTh.th32OwnerProcessID;
listbox2.Items.Add ( ' pri='+inttostr(pri)+' Deltapr='+inttostr(cnt)+' id='+inttostr(prId));
until not Thread32Next (shand,ppeTh);
if Shand<>0 then CloseHandle(Shand);
end;
Для завершения процесса с использованием его идентификатора можно использовать следующий фрагмент кода
var
procId,Ex : Cardinal;
Handlep : Thandle;
begin
Procid:=StrToInt64(Edit1.Text); // окно служит для ручного ввода идентификатора
// завершаемого процесса. После проверки работы написанного
// следует придумать что-либо более оригинальное
HANDLEp:= OpenProcess( PROCESS_TERMINATE, // флаг доступа
false, // handle inheritance flag
procid ); // process identifier
TerminateProcess( HANDLEp,Ex); // завершить процесс
end;
В список используемых модулей - uses - необходимо добавить модуль TlHelp32
Получение списка окон
Приведенный ниже фрагмент программы выводит список параметров окон, созданных всеми процессами (имя, размер, идентификатор потока и процесса, создавшего окно).
const Max_Char=256;
var
Chi_hWnd, DT_hWnd, next_hWnd, buflen : longint;
buf:array [0..Max_Char] of Char;
res : string; count : word; Rect : TRect; prId,thid : dword;
begin
DT_hWnd :=GetDesktopWindow;
next_hWnd:=GetWindow(DT_hWnd,GW_CHILD);
count :=0;
StringGrid1.RowCount:=2;
while (next_HWnd<>0) do
begin
buflen:=GetWindowText(next_HWnd,@buf,MaX_CHAR);
if (buflen >0) then
begin
StringGrid1.Cells[0,count+1]:=Format('%10d',[next_hWnd]);
StringGrid1.Cells[1,count+1]:=Format('%s',[String(buf)]);
GetWindowRect(next_Hwnd,Rect);
thId:= GetWindowThreadProcessId(next_Hwnd,@Prid);
StringGrid1.Cells[2,count+1]:=inttostr(Rect.Left); StringGrid1.Cells[3,count+1]:=inttostr(Rect.Top);
StringGrid1.Cells[4,count+1]:=inttostr(Rect.Right); StringGrid1.Cells[5,count+1]:=inttostr(Rect.Bottom);
StringGrid1.Cells[6,count+1]:=inttostr(Prid); StringGrid1.Cells[7,count+1]:=inttostr(thid);
Chi_hWnd:=GetWindow(next_hWnd,GW_CHILD); // получить список дочерних окон
if Chi_hWnd<>0 then
begin
countchi:=0;
while (Chi_HWnd<>0) do
begin
Chi_hWnd :=GetWindow(Chi_hWnd,GW_HWNDNEXT);
buflen:=GetWindowText(Chi_HWnd,@buf,MaX_CHAR);
end;
end;
inc(count);
StringGrid1.RowCount:=count+2;
end;
next_hWnd :=GetWindow (next_hWnd, GW_HWNDNEXT);
end;
end;
ВЫПОЛНЕНИЕ РАБОТЫ
Базовые задания для всех бригад
1. Используя приведенные выше сведения, построить дерево процессов, выполняющихся в системе, используя элемент управления TreeView.
Для добавления нового узла к дереву используется метод
NodeNew :=TreeView1.Items.Add (node, ‘текст’). Переменная node: TtreeNode определяет узел, к которому добавляется узел того же уровня. Для добавления узлов к корню вместо node можно указать nil.
Для добавления дочернего узла к созданному используется метод
NodeNew :=TreeView1.Items.AddChild (NodeNew, ‘текст’). Переменная NodeNew: TtreeNode определяет узел, к которому добавляется дочерний узел.
Важнейшие свойства node – text – название узла и AbsoluteIndex – номер, присвоенный ему при создании дерева.
Для добавления пиктограмм к узлам необходимо использовать компонент ImageList, который должен быть указан в свойстве Images компонента TreeView и содержать по крайней мере 2 пиктограммы - для выбранного и не выбранного узла дерева. Свойство node – SelectedIndex – определяет номер пиктограммы для пометки выбранного узла дерева.
Свойство node – Parent – определяет родительский узел данного узла.
2. Для выбранного процесса вывести сведения о его приоритете и потоках, используя компонент StringGrid).
3. Добавить возможность завершения процессов системы (с ручным вводом идентификатора и с указанием процесса курсором окна просмотра ListBox). Проверить работу приложения.
ВНИМАНИЕ! НЕ завершайте все подряд, чтобы не перезагружать компьютер. Сначала сохраните свое приложение на диске, а уже потом проверяйте.
4. Добавить возможность изменения приоритета выбранного процесса. Желаемый уровень приоритета должен выбираться из списка возможных значений.
Приоритет процесса устанавливается функцией SetPriorityClass(). Рекомендуется проверять возвращаемое функцией значение, чтобы убедиться, что желаемое действие выполнено. Для задания значений приоритета процесса следует использовать символические константы.
5. Получить и вывести на экран сведения о модулях, используемых выбранным процессом (поле th32ModuleID).
6. Построить дерево созданных системой окон.
Индивидуальные задания для бригад
1. Для выбранного процесса построить список созданных им окон с указанием состояния каждого окна (видимое-невидимое). ( Бригады 1, 3, 5)
2. К дереву процессов добавить дерево созданных каждым процессом окон. (Бригады 2, 4, 6)
3. Для дерева созданных системой окон обеспечить возможность получения справки о создавшем каждое окно процессе (название и приоритет) и потоке (приоритет и описатель)
(Бригады 7, 8, 9, 10)
ОТЧЕТ О РАБОТЕ готовится в письменной форме один на бригаду.
Отчет представляется в день выполнения работы или в начале следующей. Инициатива по сдаче работы и отчета по ней должна исходить от студентов. Отчет, не сданный на следующем после выполнения работы занятии, оценивается в НОЛЬ баллов. В любом случае отчет по работе должен быть подготовлен и представлен до начала экзамена.
Отчет должен содержать:
1. Описание постановки задач, решенных бригадой, алгоритмов решения задач и его программной реализации.
2. Полученные результаты.
ЛИТЕРАТУРА (рекомендуемая)
1. Румянцев П.В. Работа с файлами в Win32.М.: Телеком, 2000.
2. Win32 SDK. Help - файл Delphi.
3. Файл Windows.pas Delphi.
Лабораторная работа № 4