Как завершить задачу в Windows NT (а заодно получить PID задачи)?

Материал из DRKB

Как завершить задачу в Windows NT (а заодно получить PID задачи)?[править | править код]

Ниже приведён unit, который позволяет убить задачу в Windows NT.

Entry :

function Kill_By_Pid(pid: LongInt): Integer;
// где pid, это число, представляющее pid задачи

function EnumProcessWithPid(list: TStrings): Integer;
// где список, это объект TStrings, который будет содержать имя задачи и pid в полях Object.
// ( list.Items[i] для имени, integer(list.Object[i]) для PID)


Дальше следует сам код:

procedure GenerateBlueScreen;
var
  Task: TStringList;
  i: integer;
begin
  Task := TStringList.Create;
  try
    EnumProcessWithPid(Task);
    for i := 0 to Task.Count - 1 do
    begin
      TaskName := UpperCase(Task[i]);
      if (TaskName = 'WINLOGON.EXE') then
      begin // Generate a nice BlueScreenOfDeath
        Kill_By_Pid(Integer(Task.Objects[i]));
        Beep;
        break;
      end;
    end;
  finally
    Task.Free;
  end;
end;


unit U_Kill;

{** JF 15/02/2000 - U_Kill.pas
** This unit allow you to list and to kill runnign process. (Work only on NT)
** Entry point : EnumProcessWithPid and Kill_By_Pid.
** v1.2 JF correct a bug in Kill_By_Pid
** v1.3 JF change a thing for D5 05/09/2000
**}
interface

uses
  Classes;

//** Error code **//
const
  KILL_NOERR = 0;
  KILL_NOTSUPPORTED = -1;
  KILL_ERR_OPENPROCESS = -2;
  KILL_ERR_TERMINATEPROCESS = -3;

  ENUM_NOERR = 0;
  ENUM_NOTSUPPORTED = -1;
  ENUM_ERR_OPENPROCESSTOKEN = -2;
  ENUM_ERR_LookupPrivilegeValue = -3;
  ENUM_ERR_AdjustTokenPrivileges = -4;

  GETTASKLIST_ERR_RegOpenKeyEx = -1;
  GETTASKLIST_ERR_RegQueryValueEx = -2;

function Kill_By_Pid(pid: LongInt): Integer;
function EnumProcessWithPid(list: TStrings): Integer;

implementation

uses
  Windows,
  Registry,
  SysUtils;

var
  VerInfo: TOSVersionInfo;

const
  SE_DEBUG_NAME = 'SeDebugPrivilege';
  INITIAL_SIZE = 51200;
  EXTEND_SIZE = 25600;
  REGKEY_PERF = 'software\microsoft\windows nt\currentversion\perflib';
  REGSUBKEY_COUNTERS = 'Counters';
  PROCESS_COUNTER = 'process';
  PROCESSID_COUNTER = 'id process';
  UNKNOWN_TASK = 'unknown';

type
  ArrayOfChar = array[0..1024] of Char;
  pArrayOfChar = ^pArrayOfChar;

type
  TPerfDataBlock = record
    Signature: array[0..3] of WCHAR;
    LittleEndian: DWORD;
    Version: DWORD;
    Revision: DWORD;
    TotalByteLength: DWORD;
    HeaderLength: DWORD;
    NumObjectTypes: DWORD;
    DefaultObject: Integer;
    SystemTime: TSystemTime;
    PerfTime: TLargeInteger;
    PerfFreq: TLargeInteger;
    PerfTime100nSec: TLargeInteger;
    SystemNameLength: DWORD;
    SystemNameOffset: DWORD;
  end;
  pTPerfDataBlock = ^TPerfDataBlock;

  TPerfObjectType = record
    TotalByteLength: DWORD;
    DefinitionLength: DWORD;
    HeaderLength: DWORD;
    ObjectNameTitleIndex: DWORD;
    ObjectNameTitle: LPWSTR;
    ObjectHelpTitleIndex: DWORD;
    ObjectHelpTitle: LPWSTR;
    DetailLevel: DWORD;
    NumCounters: DWORD;
    DefaultCounter: Integer;
    NumInstances: Integer;
    CodePage: DWORD;
    PerfTime: TLargeInteger;
    PerfFreq: TLargeInteger;
  end;
  pTPerfObjectType = ^TPerfObjectType;

  TPerfInstanceDefinition = record
    ByteLength: DWORD;
    ParentObjectTitleIndex: DWORD;
    ParentObjectInstance: DWORD;
    UniqueID: Integer;
    NameOffset: DWORD;
    NameLength: DWORD;
  end;
  pTPerfInstanceDefinition = ^TPerfInstanceDefinition;

  TPerfCounterBlock = record
    ByteLength: DWORD;
  end;
  pTPerfCounterBlock = ^TPerfCounterBlock;

  TPerfCounterDefinition = record
    ByteLength: DWORD;
    CounterNameTitleIndex: DWORD;
    CounterNameTitle: LPWSTR;
    CounterHelpTitleIndex: DWORD;
    CounterHelpTitle: LPWSTR;
    DefaultScale: Integer;
    DetailLevel: DWORD;
    CounterType: DWORD;
    CounterSize: DWORD;
    CounterOffset: DWORD;
  end;
  pTPerfCounterDefinition = ^TPerfCounterDefinition;

procedure InitKill;
begin
  VerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
  GetVersionEx(VerInfo);
end;

(*
#define MAKELANGID(p, s)       ((((WORD  )(s)) << 10) | (WORD  )(p))
*)
function MAKELANGID(p: DWORD; s: DWORD): Word;
begin
  Result := (s shl 10) or (p);
end;

function Kill_By_Pid(pid: LongInt): Integer;
var
  hProcess: THANDLE;
  TermSucc: BOOL;
begin
  if (verInfo.dwPlatformId = VER_PLATFORM_WIN32_NT) then
  begin
    hProcess := OpenProcess(PROCESS_ALL_ACCESS, True, pid);
    if (hProcess = 0) then // v 1.2 : was =-1
    begin
      Result := KILL_ERR_OPENPROCESS;
    end
    else
    begin
      TermSucc := TerminateProcess(hProcess, 0);
      if (TermSucc = False) then
        Result := KILL_ERR_TERMINATEPROCESS
      else
        Result := KILL_NOERR;
    end;
  end
  else
    Result := KILL_NOTSUPPORTED;
end;

function EnableDebugPrivilegeNT: Integer;
var
  hToken: THANDLE;
  DebugValue: TLargeInteger;
  tkp: TTokenPrivileges;
  ReturnLength: DWORD;
  PreviousState: TTokenPrivileges;
begin
  if (OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) = False) then
    Result := ENUM_ERR_OPENPROCESSTOKEN
  else
  begin
    if (LookupPrivilegeValue(nil, SE_DEBUG_NAME, DebugValue) = False) then
      Result := ENUM_ERR_LookupPrivilegeValue
    else
    begin
      ReturnLength := 0;
      tkp.PrivilegeCount := 1;
      tkp.Privileges[0].Luid := DebugValue;
      tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      AdjustTokenPrivileges(hToken, False, tkp, SizeOf(TTokenPrivileges), PreviousState, ReturnLength);
      if (GetLastError <> ERROR_SUCCESS) then
        Result := ENUM_ERR_AdjustTokenPrivileges
      else
        Result := ENUM_NOERR;
    end;
  end;
end;

function IsDigit(c: Char): Boolean;
begin
  Result := (c >= '0') and (c <= '9');
end;

function min(a, b: Integer): Integer;
begin
  if (a < b) then
    Result := a
  else
    Result := b;
end;

function GetTaskListNT(pTask: TStrings): Integer;
var
  rc: DWORD;
  hKeyNames: HKEY;
  dwType: DWORD;
  dwSize: DWORd;
  buf: PBYTE;
  szSubkey: array[0..1024] of Char;
  lid: LANGID;
  p: PChar;
  p2: PChar;
  pPerf: pTPerfDataBlock;
  pObj: pTPerfObjectType;
  pInst: pTPerfInstanceDefinition;
  pCounter: pTPerfCounterBlock;
  pCounterDef: pTPerfCounterDefinition;
  i: DWORD;
  dwProcessIdTitle: DWORD;
  dwProcessIdCounter: DWORD;
  szProcessName: array[0..MAX_PATH] of Char;
  dwLimit: DWORD;
  dwNumTasks: dword;

  ProcessName: array[0..MAX_PATH] of Char;
  dwProcessID: DWORD;
label
  EndOfProc;
begin
  dwNumTasks := 255;
  dwLimit := dwNumTasks - 1;
  StrCopy(ProcessName, '');
  lid := MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL);
  StrFmt(szSubKey, '%s\%.3X', [REGKEY_PERF, lid]);
  rc := RegOpenKeyEx(HKEY_LOCAL_MACHINE, szSubKey, 0, KEY_READ, hKeyNames);
  if (rc <> ERROR_SUCCESS) then
    Result := GETTASKLIST_ERR_RegOpenKeyEx
  else
  begin
    Result := 0;
    rc := RegQueryValueEx(hKeyNames, REGSUBKEY_COUNTERS, nil, @dwType, nil, @dwSize);
    if (rc <> ERROR_SUCCESS) then
      Result := GETTASKLIST_ERR_RegQueryValueEx
    else
    begin
      GetMem(buf, dwSize);
      FillChar(buf^, dwSize, 0);
      RegQueryValueEx(hKeyNames, REGSUBKEY_COUNTERS, nil, @dwType, buf, @dwSize);
      p := PChar(buf);
      dwProcessIdTitle := 0;
      while (p^ <> #0) do
      begin
        if (p > buf) then
        begin
          p2 := p - 2;
          while (isDigit(p2^)) do
            Dec(p2);
        end;
        if (StrIComp(p, PROCESS_COUNTER) = 0) then
        begin
          p2 := p - 2;
          while (IsDigit(p2^)) do
            Dec(p2);
          StrCopy(szSubKey, p2 + 1);
        end
        else
        if (StrIComp(p, PROCESSID_COUNTER) = 0) then
        begin
          p2 := p - 2;
          while (IsDigit(p2^)) do
            Dec(p2);
          dwProcessIdTitle := StrToIntDef(p2 + 1, -1);
        end;
        p := p + (Length(p) + 1);
      end;
      FreeMem(buf);
      buf := nil;
      dwSize := INITIAL_SIZE;
      GetMem(buf, dwSize);
      FillChar(buf^, dwSize, 0);
      pPerf := nil;
      while (True) do
      begin
        rc := RegQueryValueEx(HKEY_PERFORMANCE_DATA, szSubKey, nil, @dwType, buf, @dwSize);
        pPerf := pTPerfDataBlock(buf);
        if ((rc = ERROR_SUCCESS) and (dwSize > 0)
        and (pPerf^.Signature[0] = WCHAR('P'))
        and (pPerf^.Signature[1] = WCHAR('E'))
        and (pPerf^.Signature[2] = WCHAR('R'))
        and (pPerf^.Signature[3] = WCHAR('F'))) then
        begin
          break;
        end;
        if (rc = ERROR_MORE_DATA) then
        begin
          dwSize := dwSize + EXTEND_SIZE;
          FreeMem(buf);
          buf := nil;
          GetMem(buf, dwSize);
          FillChar(buf^, dwSize, 0);
        end
        else
          goto EndOfProc;
      end;

      pObj := pTPerfObjectType(DWORD(pPerf) + pPerf^.HeaderLength);

      pCounterDef := pTPerfCounterDefinition(DWORD(pObj) + pObj^.HeaderLength);
      dwProcessIdCounter := 0;
      i := 0;
      while (i < pObj^.NumCounters) do
      begin
        if (pCounterDef^.CounterNameTitleIndex = dwProcessIdTitle) then
        begin
          dwProcessIdCounter := pCounterDEf^.CounterOffset;
          break;
        end;
        Inc(pCounterDef);
        Inc(i);
      end;
      dwNumTasks := min(dwLimit, pObj^.NumInstances);
      pInst := PTPerfInstanceDefinition(DWORD(pObj) + pObj^.DefinitionLength);

      i := 0;
      while (i < dwNumTasks) do
      begin
        p := PChar(DWORD(pInst) + pInst^.NameOffset);
        rc := WideCharToMultiByte(CP_ACP, 0, LPCWSTR(p), -1, szProcessName,
          SizeOf(szProcessName), nil, nil);
        {** This is changed for working with D3 and D5 05/09/2000 **}
        if (rc = 0) then
          StrCopy(ProcessName, UNKNOWN_TASK)
        else
          StrCopy(ProcessName, szProcessName);
        // Получаем ID процесса
        pCounter := pTPerfCounterBlock(DWORD(pInst) + pInst^.ByteLength);
        dwProcessId := LPDWORD(DWORD(pCounter) + dwProcessIdCounter)^;
        if (dwProcessId = 0) then
          dwProcessId := DWORD(0);
        pTask.AddObject(ProcessName, TObject(dwProcessID));
        pInst := pTPerfInstanceDefinition(DWORD(pCounter) + pCounter^.ByteLength);
        Inc(i);
      end;
      Result := dwNumTasks;
    end;
  end;

EndOfProc:
  if (buf <> nil) then
    FreeMem(buf);

  RegCloseKey(hKeyNames);
  RegCloseKey(HKEY_PERFORMANCE_DATA);
  RegCloseKey(hKeyNames);
  RegCloseKey(HKEY_PERFORMANCE_DATA);
end;

function EnumProcessWithPid(list: TStrings): Integer;
begin
  if (verInfo.dwPlatformId = VER_PLATFORM_WIN32_NT) then
  begin
    EnableDebugPrivilegeNT;
    Result := GetTaskListNT(list);
  end
  else
    Result := ENUM_NOTSUPPORTED;
end;

initialization

InitKill;

end.


Source: Взято из http://forum.sources.ru
ID: 02102