Delphi - Indy 关闭所有与客户相关的表格

Delphi - Indy close all the forms that related to client

一旦客户端与服务器断开连接,我将尝试关闭与客户端相关的所有表单

此操作将在服务器端进行。

我有(我在 运行 时间知道的)例如每个客户的部分唯一标题

表单标题 1:

ServiceA - ClientABC

表单标题 2:

ServiceB - ClientABC

我已经知道的只是 - ClientABC 部分。

因此,当客户端 ClientABC 与我的服务器断开连接时,我想关闭服务器端所有相关打开的表单。

procedure TIdServer.ClientRemove(const AContext: TIdContext);
var
   sTitle: string;
  function CloseChildForm(Wnd: HWND; Param: LPARAM): BOOL; stdcall;
  begin
       if Pos(sTitle, _GetWindowTitle(Wnd)) <> 0 then
          PostMessage(Wnd, WM_CLOSE, 0, 0);
       Result := True;
  end;
begin
     sTitle := TMyContext(AContext).Uniquename {ClientABC}
     if Assigned(FListView) then begin
        TThread.Queue(nil,
          procedure
          var
            i: Integer;
          begin
               EnumWindows(@CloseChildForm, 0);

               .......

               end;

          end
        );
     end;
end;

我的问题是 CloseChildForm 函数中的字符串 sTitle 总是空的。

我在 IdServerDisconnect 过程中调用 ClientRemove

procedure TIdServer.IdServerDisconnect(AContext: TIdContext);
begin
     TMyContext(AContext).Queue.Clear;
     ........
     ClientRemove(AContext);
end;

谁能告诉我哪里错了?

这里有很多错误:

  • 您不得使用嵌套函数作为回调。语言不允许这样做,您的代码只能编译,因为 EnumWindows 的 RTL 声明使用回调参数的无类型指针。
  • TThread.Queue 的异步执行意味着封闭堆栈帧可以在对 EnumWindows 的调用完成之前完成。
  • 您有关闭不属于您进程的 windows 的危险。

如果我遇到这个问题,我会使用 Screen.Forms[] 来解决它。像这样:

for i := Screen.FormCount-1 downto 0 do
  if CaptionMatches(Screen.Forms[i]) then
    Screen.Forms[i].Close; 

这只是一个大纲。我相信你能理解这个概念。关键是不要使用 EnumWindows 而是使用 VCL 自己的机制来枚举您的表单。