2012-02-02 1 views
4

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

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

ответ

11

Позвоните по телефону OpenProcess, чтобы получить дескриптор процесса. Достаточно будет права доступа SYNCHRONIZE. Затем подождите на ручке. Что-то вроде:

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

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

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

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

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

+0

Почему downvote? – RRUZ

1

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

Вы можете использовать EnumProcesses(), чтобы узнать, какие процессы в данный момент запущены, а затем захватить их имена файлов и идентификаторы процессов и т. Д. См. this example на MSDN.

+0

Вопрос об уведомлении об отключении. Надеюсь, вы не предлагаете опрос? –

+0

Да, я был, и ОП спрашивал об этой возможности. Я не знал о '__InstanceDeletionEvent'. –

+0

Ну, ожидание на ручке процесса выглядит как лучшее решение для меня. –

Смежные вопросы