1

我有进程的ID。这个过程是一个有一个主窗口的应用程序。我正在尝试通过将 WM_CLOSE 发送到其主窗口来关闭此应用程序。我正在使用搜索其主窗口EnumWindows

问题是,我尝试关闭的这个应用程序并不总是关闭。它是多线程应用程序。当我使用下面介绍的相同方法时,记事本和 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.
4

1 回答 1

3

在此处查看此知识库文章,了解如何尽可能干净地关闭另一个应用程序。到目前为止,你做得对。文章建议你

  • 首先将 WM_CLOSE 发布到应用程序的所有窗口(因为您无法确定哪个是主窗口)。
  • 等待超时,如果超时过去
  • 使用 TerminateProcess 杀死应用程序

我同意。

于 2011-08-02T09:38:20.110 回答