У меня есть имя службы для службы Windows в Delphi, и я также знаю, как получить от нее дескриптор. Что мне нужно сделать, так это остановить службу, и если по какой-то причине остановка не удалась, мне нужно убить процесс, связанный со службой. Проблема в том, что у меня есть несколько служб, работающих с одним и тем же исполняемым файлом, поэтому я не могу использовать имя исполняемого файла для завершения процесса. Это означает, что мне нужен идентификатор процесса, чтобы убить соответствующий связанный процесс. Как я могу получить этот идентификатор или какой-либо способ убить правильный процесс из имени или дескриптора службы?
Как найти идентификатор процесса по имени/дескриптору службы в Delphi?
Ответы (3)
person
Jk.
schedule
22.01.2009
Это не похоже на решение для delphi, я действительно не ищу решение на другом языке для этого, к которому мне придется подключиться. @Arkadiy - убийство процесса не является большой проблемой, текущая система делает это, но не различает, когда запущено несколько процессов.
- person Chris J; 22.01.2009
Крис, Jk связан с функцией API QueryServiceStatusEx. Вы можете вызывать его с любого языка, включая Delphi. Вам не нужно привязываться к другому языку. Вы постоянно вызываете функции API: например, все, что вы когда-либо вызывали из модуля Windows.
- person Rob Kennedy; 22.01.2009
Вызов дает идентификатор процесса, а также статус, поэтому должно быть то, что нужно.
- person mj2008; 22.01.2009
Мне было трудно понять, как использовать вызов в Delphi, я понял это в другом ответе на этот вопрос.
- person Chris J; 22.01.2009
Обратите внимание, что я принял это решение только для того, чтобы было принято полное решение для кода Delphi, и все это благодаря Jk, хотя и за то, что он указал мне правильный путь.
--
Хорошо, я смог понять, как использовать ответ Jk, и придумал это решение в delphi.
Для справки, это ссылка, предоставленная Jk:
Мое решение:
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
на самом деле это код, который я заменяю, этот код дает сбой в ситуациях, когда несколько разных процессов запускаются из одного и того же исполняемого файла. В нашем случае мы запускаем несколько исполняемых файлов одновременно как отдельные сервисы и должны иметь возможность управлять отдельным, правильным процессом по сервису.
- person Chris J; 26.01.2009