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 に答える