我有一个适用于Skype API的Delphi 6应用程序。我想知道Skype客户端何时关闭,即使我的软件没有启动它(因此我没有处理它的进程句柄)。通过这种方式,我可以知道用户是否关闭Skype客户端我可以非常轻松地获取Skype客户端的进程ID,因此是否有Windows API调用或其他接受进程ID的技术,我可以在进程中获取通知(Skype客户端)已经终止?
如果没有,是否有一个WinApi调用,我可以使用它来轮询Windows以查看进程ID是否仍然有效,或者Windows是否重用进程ID,因此我有可能最终获得进程ID属于最近推出的不是Skype客户端的流程,这会使我的民意调查无效?
答案 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。