仅具有进程 ID 时关闭主应用程序窗口时出现问题

发布于 2024-11-27 14:08:40 字数 2477 浏览 3 评论 0原文

我有进程的 ID。该进程是一个具有主窗口的应用程序。 我试图通过向其主窗口发送 WM_CLOSE 来关闭该应用程序。 我正在使用 EnumWindows 搜索其主窗口。

问题是,我尝试关闭的这个应用程序并不总是关闭。 它是多线程应用程序。当我使用下面介绍的相同方法时,记事本和计算器总是关闭。但我不确定它是否正常工作,因为它返回给我同一个窗口的许多句柄,即使对于 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.

I have ID of the process. This process is an application which have a main window.
I am trying to close this application by sending WM_CLOSE to its main window.
I am searching its main window by using EnumWindows.

The problem is, that this application which I try to close, does not close always.
It is multithreaded application. Notepad and Calc are always closing when I use the same method which is presented below. But I am not sure if it is working properly cause it returns me many handles to the same window, even for Calc.exe.

Is it possible that thread is taking a handle to window and then this handle somehow become corrupted? Or maybe I should not use GetWindowThreadProcessId(hHwnd,pPid) but some other function in the callback?

I am out of ideas, would be grateful for any help. Thanks.

Code snippet:

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

世界和平 2024-12-04 14:08:40

请参阅此处这篇知识库文章,了解如何尽可能干净地关闭另一个应用程序。到目前为止你做得对。本文建议您

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

我同意。

Have a look in this Knowledge Base Article here on how to close another application as cleanly as possible. You are doing it right so far. The Article suggests that you

  • first post WM_CLOSE to all windows of the application (since you cannot know for sure which one is the main).
  • wait with a timeout and if the timeout elapses
  • kill the application using TerminateProcess

I agree.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文