Проблемы с закрытием главного окна приложения при наличии только идентификатора его процесса - PullRequest
1 голос
/ 02 августа 2011

У меня есть идентификатор процесса. Этот процесс представляет собой приложение, которое имеет главное окно. Я пытаюсь закрыть это приложение, отправив WM_CLOSE в главное окно. Я ищу в главном окне, используя EnumWindows.

Проблема в том, что это приложение, которое я пытаюсь закрыть, не всегда закрывается. Это многопоточное приложение. Notepad и Calc всегда закрываются, когда я использую один и тот же метод, который представлен ниже. Но я не уверен, что он работает должным образом, потому что он возвращает мне много дескрипторов к одному и тому же окну, даже для Calc.exe.

Возможно ли, что поток переносит дескриптор окна, а затем этот дескриптор как-то повреждается? Или, может быть, я не должен использовать GetWindowThreadProcessId(hHwnd,pPid), но какую-то другую функцию в обратном вызове?

У меня нет идей, буду благодарен за любую помощь. Спасибо.

Фрагмент кода:

unit Unit22;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm22 = class(TForm)
    edtprocID: TEdit;
    lblEnterProcessID: TLabel;
    btnCloseProcessWindow: TButton;
    lblStatus: TLabel;
    procedure btnCloseProcessWindowClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  THandleAndHWND = record
    ProcID: THandle;
    WindowHandle: HWND;
  end;

var
  Form22: TForm22;

var
  HandleAndHWNDArray: array of THandleAndHWND;
  HandeIndex, lp: Integer;

implementation

{$R *.dfm}

function EnumProcess(hHwnd: HWND; lParam : integer): boolean; stdcall;
var
  pPid : DWORD;
begin
  //if the returned value in null the
  //callback has failed, so set to false and exit.
  if (hHwnd=0) then
  begin
    result := false;
  end else
  begin
    GetWindowThreadProcessId(hHwnd,pPid);
    Inc(HandeIndex);
    HandleAndHWNDArray[HandeIndex].ProcID := pPid;
    HandleAndHWNDArray[HandeIndex].WindowHandle := hHwnd;
    Result := true;
  end;

end;

procedure TForm22.btnCloseProcessWindowClick(Sender: TObject);
var
  ProcID: Cardinal;
  i, LastError: Integer;
begin
  HandeIndex := -1;
  ProcID := StrToInt(edtprocID.Text);

  SetLength(HandleAndHWNDArray, 3000);
  EnumWindows(@EnumProcess,lp);

  for i := 0 to HandeIndex do //After EnumWindows HandleIndex is above 500 despite the fact that I have like 10 openned windows max
  begin                       //That means that EnumWindows was called 500 times?
    if HandleAndHWNDArray[i].ProcID =  ProcID then //search for process equal to procces ID given by the user
    begin
      //if we have a processID then we have a handle to its main window
      if PostMessage(HandleAndHWNDArray[i].WindowHandle, WM_CLOSE, 0, 0) then
      begin
        lblStatus.Caption := 'message posted!';
      end else
      begin
        LastError := GetLastError;
        lblStatus.Caption := Format('Error: [%d] ' + SysErrorMessage(LastError), [LastError]);
      end;
      Exit;
    end;
  end;

end;

end.

1 Ответ

3 голосов
/ 02 августа 2011

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

  • впервые опубликовали WM_CLOSE на всех окнах приложения (поскольку вы не можете точно знать, какое из них является основным).
  • ждатьс таймаутом, и если тайм-аут истекает
  • , убейте приложение, используя TerminateProcess

Я согласен.

...