Могу ли я получить уведомление о том, что не запущенный мной процесс завершает работу в Windows XP / 7? - PullRequest
5 голосов
/ 03 февраля 2012

У меня есть приложение Delphi 6, которое работает со Skype API. Я хочу знать, когда клиент Skype был закрыт, хотя мое программное обеспечение не запускало его (поэтому у меня нет дескриптора процесса для него). Таким образом, я могу узнать, если пользователь выключил клиент Skype, я могу довольно легко получить идентификатор процесса для клиента Skype, так что есть ли вызов API Windows или другой метод, который принимает идентификатор процесса, где я могу получить уведомление, когда процесс (Клиент Skype) прекратил работу?

Если нет, есть ли вызов WinApi, который я могу использовать для опроса Windows, чтобы узнать, является ли идентификатор процесса все еще действительным, или же Windows повторно использует идентификаторы процесса, так что есть шанс, что я могу получить идентификатор процесса, принадлежащий недавно запущенный процесс, который не является клиентом Skype, который сделает недействительными мои попытки опроса?

Ответы [ 3 ]

12 голосов
/ 03 февраля 2012

Вызовите OpenProcess , чтобы получить дескриптор процесса. Право доступа SYNCHRONIZE, вероятно, будет достаточно. Тогда подожди на ручке. Что-то вроде:

HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid);
WaitForSingleObject(hProcess, INFINITE);
CloseHandle(hProcess);
6 голосов
/ 03 февраля 2012

Вы можете использовать встроенное событие WMI __InstanceDeletionEvent для мониторинга класса Win32_Process и фильтра по свойству ProcessId, это событие выполняется в асинхронном режиме код.

Проверьте этот пример кода (написан на Delphi XE2, но должен работать в Delphi 6 без проблем)

Примечание. Прежде чем использовать ее, необходимо импортировать библиотеку Microsoft WMI Scripting V1.2.

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, WbemScripting_TLB;

type
  TWmiAsyncEvent = class
  private
    FWQL      : string;
    FSink     : TSWbemSink;
    FLocator  : ISWbemLocator;
    FServices : ISWbemServices;
    procedure EventReceived(ASender: TObject; const objWbemObject: ISWbemObject; const objWbemAsyncContext: ISWbemNamedValueSet);
  public
    procedure  Start;
    constructor Create(Pid : DWORD);
    Destructor Destroy;override;
  end;

  TFrmDemo = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    AsyncEvent : TWmiAsyncEvent;
  public
    { Public declarations }
  end;

var
  FrmDemo: TFrmDemo;

implementation

{$R *.dfm}

uses
 ActiveX;

{ TWmiAsyncEvent }

constructor TWmiAsyncEvent.Create(Pid: DWORD);
begin
  inherited Create;
  CoInitializeEx(nil, COINIT_MULTITHREADED);
  FLocator  := CoSWbemLocator.Create;
  FServices := FLocator.ConnectServer('.', 'root\CIMV2', '', '', '', '', wbemConnectFlagUseMaxWait, nil);
  FSink     := TSWbemSink.Create(nil);
  FSink.OnObjectReady := EventReceived;
  //construct the WQL sentence with the pid to monitor
  FWQL:=Format('Select * From __InstanceDeletionEvent Within 1 Where TargetInstance ISA "Win32_Process"  And TargetInstance.ProcessId=%d',[Pid]);

end;

destructor TWmiAsyncEvent.Destroy;
begin
  if FSink<>nil then
    FSink.Cancel;
  FLocator  :=nil;
  FServices :=nil;
  FSink     :=nil;
  CoUninitialize;
  inherited;
end;

procedure TWmiAsyncEvent.EventReceived(ASender: TObject;
  const objWbemObject: ISWbemObject;
  const objWbemAsyncContext: ISWbemNamedValueSet);
var
  PropVal: OLEVariant;
begin      
  PropVal := objWbemObject;
  //do something when the event is received.
  ShowMessage(Format('The Application %s Pid %d was finished',[String(PropVal.TargetInstance.Name), Integer(PropVal.TargetInstance.ProcessId)]));
end;


procedure TWmiAsyncEvent.Start;
begin
 FServices.ExecNotificationQueryAsync(FSink.DefaultInterface,FWQL,'WQL', 0, nil, nil);
end;

procedure TFrmDemo.FormCreate(Sender: TObject);
begin
    //here you must pass the pid of the process
    AsyncEvent:=TWmiAsyncEvent.Create(1852);
    AsyncEvent.Start;
end;

procedure TFrmDemo.FormDestroy(Sender: TObject);
begin
  AsyncEvent.Free;
end;

end.

Для получения дополнительной информации вы можете проверить эту статью Delphi and WMI Events

1 голос
/ 03 февраля 2012

Windows повторно использует идентификаторы процессов, поэтому не полагайтесь на них сами по себе.

Вы можете использовать EnumProcesses(), чтобы узнать, какие процессы выполняются в данный момент, затем получить их имена файлов и идентификаторы процессов и т. Д.1004 * этот пример в MSDN.

...