我是否可以获得有关我未生成的进程在Windows XP / 7中关闭的通知?

时间:2012-02-02 22:31:17

标签: delphi winapi process skype

我有一个适用于Skype API的Delphi 6应用程序。我想知道Skype客户端何时关闭,即使我的软件没有启动它(因此我没有处理它的进程句柄)。通过这种方式,我可以知道用户是否关闭Skype客户端我可以非常轻松地获取Skype客户端的进程ID,因此是否有Windows API调用或其他接受进程ID的技术,我可以在进程中获取通知(Skype客户端)已经终止?

如果没有,是否有一个WinApi调用,我可以使用它来轮询Windows以查看进程ID是否仍然有效,或者Windows是否重用进程ID,因此我有可能最终获得进程ID属于最近推出的不是Skype客户端的流程,这会使我的民意调查无效?

3 个答案:

答案 0 :(得分:12)

致电OpenProcess以获取流程处理。 SYNCHRONIZE访问权限可能就足够了。然后等待手柄。类似的东西:

HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid);
WaitForSingleObject(hProcess, INFINITE);
CloseHandle(hProcess);

答案 1 :(得分:6)

您可以使用__InstanceDeletionEvent WMI内部事件来监视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

答案 2 :(得分:1)

Windows会重复使用进程ID,因此请不要单独依赖它。

您可以使用EnumProcesses()了解当前正在运行的进程,然后获取其文件名和进程ID等。请参阅MSDN上的this example