Как найти идентификатор процесса по имени/дескриптору службы в Delphi?

У меня есть имя службы для службы Windows в Delphi, и я также знаю, как получить от нее дескриптор. Что мне нужно сделать, так это остановить службу, и если по какой-то причине остановка не удалась, мне нужно убить процесс, связанный со службой. Проблема в том, что у меня есть несколько служб, работающих с одним и тем же исполняемым файлом, поэтому я не могу использовать имя исполняемого файла для завершения процесса. Это означает, что мне нужен идентификатор процесса, чтобы убить соответствующий связанный процесс. Как я могу получить этот идентификатор или какой-либо способ убить правильный процесс из имени или дескриптора службы?


person Chris J    schedule 22.01.2009    source источник


Ответы (3)


QueryServiceStatusEx?

person Jk.    schedule 22.01.2009
comment
Это не похоже на решение для delphi, я действительно не ищу решение на другом языке для этого, к которому мне придется подключиться. @Arkadiy - убийство процесса не является большой проблемой, текущая система делает это, но не различает, когда запущено несколько процессов. - person Chris J; 22.01.2009
comment
Крис, Jk связан с функцией API QueryServiceStatusEx. Вы можете вызывать его с любого языка, включая Delphi. Вам не нужно привязываться к другому языку. Вы постоянно вызываете функции API: например, все, что вы когда-либо вызывали из модуля Windows. - person Rob Kennedy; 22.01.2009
comment
Вызов дает идентификатор процесса, а также статус, поэтому должно быть то, что нужно. - person mj2008; 22.01.2009
comment
Мне было трудно понять, как использовать вызов в Delphi, я понял это в другом ответе на этот вопрос. - person Chris J; 22.01.2009

Обратите внимание, что я принял это решение только для того, чтобы было принято полное решение для кода Delphi, и все это благодаря Jk, хотя и за то, что он указал мне правильный путь.

--

Хорошо, я смог понять, как использовать ответ Jk, и придумал это решение в delphi.

Для справки, это ссылка, предоставленная Jk:

QueryServiceStatusEx

Мое решение:

unit Demo;

interface

uses
  Windows, Forms, SysUtils,
  StdCtrls, WinSvc, Controls, Classes;

type

  //Form for basic demo usage
  TForm6 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  end;

  //Record defined for use as return buffer
  _SERVICE_STATUS_PROCESS = record
    dwServiceType: DWORD;
    dwCurrentState: DWORD;
    dwControlsAccepted: DWORD;
    dwWin32ExitCode: DWORD;
    dwServiceSpecificExitCode: DWORD;
    dwCheckPoint: DWORD;
    dwWaitHint: DWORD;
    dwProcessId: DWORD;
    dwServiceFlags: DWORD;
  end;
  //Function Prototype
  function QueryServiceStatusEx(
  SC_HANDLE: SC_Handle;
  SC_STATUS_TYPE: Cardinal;
  out lpBuffer: _SERVICE_STATUS_PROCESS;
  cbBufSize: DWORD;
  out pcbBytesNeeded: LPDWORD
  ): BOOL; stdcall;


  //internal setup function
  function GetPid(sService: String; sMachine: String = '') : Cardinal;
var
  Form6: TForm6;

implementation

{$R *.dfm}
const
  // windows api library
  advapi32 = 'advapi32.dll';
  //define the api call
  function QueryServiceStatusEx;   external advapi32 name 'QueryServiceStatusEx';

//for demo usage
procedure TForm6.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Add(IntToStr(Integer(GetPid('Service'))))
end;


function GetPid(sService: String; sMachine: String = '') : Cardinal;
var
  schm,
  schs: SC_Handle;
  SC_STATUS_TYPE: Cardinal;
  lpBuffer: _SERVICE_STATUS_PROCESS;
  cbBufSize: DWORD;
  pcbBytesNeeded: LPDWORD;
begin
  //open the service manager  (defined in WinSvc)
  schm := OpenSCManager(PChar(sMachine), nil, SC_MANAGER_CONNECT);
  //set the status type to SC_STATUS_PROCESS_INFO
  //this is currently the only value supported
  SC_STATUS_TYPE := $00000000;
  //set the buffer size to the size of the record
  cbBufSize := sizeof(_SERVICE_STATUS_PROCESS);
  if (schm>0) then
  begin
    //grab the service handle
    schs := OpenService(schm, PChar(sService), SERVICE_QUERY_STATUS);
    if (schs>0) then
    begin
      //call the function
      QueryServiceStatusEx(
      schs,
      SC_STATUS_TYPE,
      lpBuffer,
      cbBufSize,
      pcbBytesNeeded);
      CloseServiceHandle(schs);
    end;
    CloseServiceHandle(schm);
  end;
  Result := lpBuffer.dwProcessId;
end;



end.

Обратите внимание, что не все внешние имена и другие потребности включены.

person Chris J    schedule 22.01.2009

Или используйте DSiWin32 для многих полезных функций, включая DSiGetProcessID. Этот код был написан пользователем (и программистом) StackOverflow Габром.

Вот функция, для справки. Это даст вам то, что вы ищете:

//Retrieves ID of the specified process. Requires Toolhelp API.
//  @returns False if ID cannot be retrieved. Check GetLastError - if it is 0, process
//       doesn't exist; otherwise it contains the Win32 error code.
//  @author  gabr
//  @since   2004-02-12
//
  function DSiGetProcessID(const processName: string; var processID: DWORD): boolean;
  var
    hSnapshot: THandle;
    procEntry: TProcessEntry32;
  begin
    Result := false;
    hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if hSnapshot = 0 then
      Exit;
    try
      procEntry.dwSize := Sizeof(procEntry);
      if not Process32First(hSnapshot, procEntry) then
        Exit;
      repeat
        if AnsiSameText(procEntry.szExeFile, processName) then begin
          processID := procEntry.th32ProcessID;
          Result := true;
          break; // repeat
        end;
      until not Process32Next(hSnapshot, procEntry);
    finally DSiCloseHandleAndNull(hSnapshot); end;
  end; { DSiGetProcessID }
person Mick    schedule 23.01.2009
comment
на самом деле это код, который я заменяю, этот код дает сбой в ситуациях, когда несколько разных процессов запускаются из одного и того же исполняемого файла. В нашем случае мы запускаем несколько исполняемых файлов одновременно как отдельные сервисы и должны иметь возможность управлять отдельным, правильным процессом по сервису. - person Chris J; 26.01.2009