You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux环境下Lazarus通过第三方进程PID获取窗口句柄的方法

在Linux Lazarus中通过PID获取窗口句柄的实现方法

在Linux平台下,并没有和Windows EnumThreadWindows 完全对应的函数——因为X11窗口系统的模型和Windows不同。但可以通过遍历所有X11窗口,读取窗口的_NET_WM_PID属性来匹配目标进程的PID,从而找到对应的窗口句柄(X11中对应Window类型,等价于Windows的HWND)。

实现步骤与代码示例

  1. 依赖准备
    确保你的Lazarus项目链接了X11库:在项目设置的Linking选项中,添加-lX11到Other linker options。同时需要在代码中引用X, Xlib, Xutil单元。

  2. 核心实现代码

uses
  X, Xlib, Xutil, Classes;

function GetWindowsByPID(Display: PDisplay; TargetPID: LongWord): TList<Window>;
var
  RootWindow, ParentWindow: Window;
  ChildWindows: PWindow;
  ChildCount: Cardinal;
  WM_PID_Atom: TAtom;
  PropType: TAtom;
  PropFormat: Integer;
  PropItems: Cardinal;
  PropBytesAfter: Cardinal;
  PropData: PLongWord;
  i: Integer;
  CurrentWindow: Window;
  CurrentPID: LongWord;
begin
  Result := TList<Window>.Create;
  if Display = nil then Exit;

  WM_PID_Atom := XInternAtom(Display, '_NET_WM_PID', False);
  if WM_PID_Atom = None then Exit;

  // 获取根窗口的子窗口列表
  if not XQueryTree(Display, DefaultRootWindow(Display), @RootWindow, @ParentWindow, @ChildWindows, @ChildCount) then Exit;

  try
    for i := 0 to ChildCount - 1 do
    begin
      CurrentWindow := ChildWindows^[i];
      // 获取当前窗口的_NET_WM_PID属性
      if XGetWindowProperty(Display, CurrentWindow, WM_PID_Atom, 0, 1, False, XA_CARDINAL,
        @PropType, @PropFormat, @PropItems, @PropBytesAfter, PPointer(@PropData)) = Success then
      begin
        if (PropType = XA_CARDINAL) and (PropFormat = 32) and (PropItems = 1) then
        begin
          CurrentPID := PropData^;
          if CurrentPID = TargetPID then
            Result.Add(CurrentWindow);
        end;
        XFree(PropData);
      end;

      // 递归遍历子窗口
      Result.AddRange(GetWindowsByPID(Display, TargetPID));
    end;
  finally
    XFree(ChildWindows);
  end;
end;

// 使用示例
procedure TForm1.Button1Click(Sender: TObject);
var
  Display: PDisplay;
  TargetPID: LongWord;
  WindowList: TList<Window>;
  i: Integer;
begin
  Display := XOpenDisplay(nil);
  if Display = nil then
  begin
    ShowMessage('无法连接到X服务器');
    Exit;
  end;

  try
    TargetPID := 1234; // 替换为目标进程的PID
    WindowList := GetWindowsByPID(Display, TargetPID);
    try
      if WindowList.Count > 0 then
      begin
        ShowMessage(Format('找到 %d 个属于PID %d 的窗口', [WindowList.Count, TargetPID]));
        for i := 0 to WindowList.Count - 1 do
          ShowMessage(Format('窗口句柄: %d', [WindowList[i]]));
      end
      else
        ShowMessage('未找到对应PID的窗口');
    finally
      WindowList.Free;
    end;
  finally
    XCloseDisplay(Display);
  end;
end;

关键说明

  • _NET_WM_PID是X11标准扩展属性,绝大多数现代桌面程序都会设置这个属性,用来关联窗口和所属进程。
  • 递归遍历是为了覆盖所有嵌套的窗口(比如应用程序的子对话框、工具栏窗口等)。
  • X11的Window类型就是Linux下的窗口句柄,和Windows的HWND作用一致,可以用来执行窗口操作(比如移动、关闭等)。

注意事项

  • 部分老旧或极简X11程序可能没有实现_NET_WM_PID属性,这种情况无法通过该方法匹配PID。
  • 确保程序运行时DISPLAY环境变量正确设置(通常默认已经配置好,远程桌面场景需要手动指定)。

内容的提问来源于stack exchange,提问作者prostor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 06:47:57