страничка tripsin'а


Главная | Статьи | Заметки | Файлы| Ссылки | я
Назад

 

Получение списка процессов. 6 часть. Terminal Services API

Скачай демонстрационный проект (26,1 кб)

Наконец последний способ, который мы тут рассмотрим – это использование Terminal Services API. Наверное ты знаешь, что в Windows имеется сервер терминалов. То есть на одной машине могут одновременно работать несколько пользователей. Применительно к локальной машине с Windows XP это выражается в наличии технологии Fast User Switching - быстрого переключения пользователей. Это в общем-то эмуляция многопользовательского режима. Пользователей как бы подключено несколько, а работать может все равно только один. Но процессы, запущенные другими пользователями, все равно остаются в памяти. Чтобы убедиться жми Alt-Ctrl-Del. Появится диспетчер задач. На его вкладке  процессы внизу есть галочка «Отображать процессы всех пользователей». Взведи ее и увидишь все запущенные процессы и имена запустивших их пользователей. Для работы с сервером терминалов и существует библиотека Terminal Services API. Вся она находится в Wtsapi32.dll  и существует начиная с Microsoft Windows NT 4.0 SP4 Terminal Server Edition. Эта библиотека пользуется другой либой - winsta.dll, и для получения процессов импортирует из нее недокументированные функции WinStationGetAllProcesses и WinStationEnumerateProcesses, которые для своей работы используют RPC (rpcrt4.dll). Дальше в механизмы удаленного вызова процедур мы лезть не будем, т.к. оно нам и не надо :) .

Для нашей задачи понадобится только одна функция WTSEnumerateProcesses:

 

 

function WTSEnumerateProcesses(

      hServer: THandle;

      Reserved,

      Version: DWORD;

      var ppProcessInfo: PWTS_PROCESS_INFO;

      var Count: DWORD

    ): BOOL;

 

hServer – идентификатор терминального сервера. Он получается функцией WTSOpenServer(имя сервера) или можно воспользоваться константой WTS_CURRENT_SERVER_HANDLE = 0 для обозначения локального компьютера. Для получения имен всех терминальных серверов в домене можно использовать функцию NetServerEnum , которой в типе требуемого сервера передать SV_TYPE_TERMINALSERVER = 0x02000000;

 

Reserved – должно быть равно 0;

 

Version – версия запроса. Должно бать равна 1.

 

ppProcessInfo – Получаем сюда указатель на массив структур WTS_PROCESS_INFO

 

Count – количесво структур WTS_PROCESS_INFO, в полученном массиве.

 

Описание структуры возвращаемой WTSEnumerateProcesses:

  WTS_PROCESS_INFO = packed record

    SessionId: DWORD;    // идентификатор сессии, из которой запущен процесс

    ProcessId: DWORD;    // идентификатор процесса (pid)

    pProcessName: PChar; // Указатель на строку с именем процесса

    pUserSid: PSID;      // указатель на SID (идентификатор безопасности)

                         // пользователя, владельца процесса.

  end;

 

 

После вызова WTSEnumerateProcesses надо обязательно вызывать WTSFreeMemory, чтобы освободить память занятую под массив структур, т.к. Винда это за тебя не сделает и будет неслабая утечка ресурсов. Для получения более подробной информации о сессии используй функцию WTSQuerySessionInformation.

unit Sample6;

interface
uses Classes;
function FillProcessesList(var slProcesses: TStringList): Boolean;

implementation

uses Windows, SysUtils;

const
  WTS_CURRENT_SERVER_HANDLE = 0;

type
  PWTS_PROCESS_INFO = ^WTS_PROCESS_INFO;
  WTS_PROCESS_INFO = packed record
    SessionId: DWORD;
    ProcessId: DWORD;
    pProcessName: PChar;
    pUserSid: PSID;
  end;

function WTSEnumerateProcesses(hServer: THandle; Reserved,Version: DWORD;
                               var ppProcessInfo: PWTS_PROCESS_INFO;
                               var Count: DWORD): BOOL; stdcall;
                               external 'wtsapi32.dll'
                               name 'WTSEnumerateProcessesA';

procedure WTSFreeMemory(pMemory: Pointer); stdcall;
                               external 'wtsapi32.dll'
                               name 'WTSFreeMemory';


function FillProcessesList(var slProcesses: TStringList): Boolean;
var
  Count, i: DWORD;
  pProcessInfo, pCur: PWTS_PROCESS_INFO;
  sProcessName: String;
begin
  if WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE,
                           0,1,pProcessInfo,Count)then
  begin
    for i := 0 to Count - 1 do
    begin
      pCur := Ptr(DWORD(pProcessInfo) + (i * SizeOf(WTS_PROCESS_INFO)));
      if Length(pCur.pProcessName) = 0 then sProcessName := '<íåèçâåñòíî>'
      else sProcessName := pCur.pProcessName;
      slProcesses.Add('Name: ' + sProcessName +
      ' PID: ' + IntToStr(pCur.ProcessId) +
      ' Session ID: ' + IntToStr(pCur.SessionId));
    end;
    WTSFreeMemory(pProcessInfo);
    Result := True;
  end
  else
    Result := False;
end;

end.

Есть конечно же и другие способы получения списка процессов. Например, здесь не рассмотрена WMI. Но для начала, я думаю, тебе и этих хватит :) . За сим позволь откланяться.

 

Назад

 


(с) tripsin aka Орехов Роман, 2006 г., tripsin@yandex.ru

Hosted by uCoz