2016-06-19 20 views
1

我试图关闭所有一次,他断开形式的服务器德尔福 - 印地关闭所有相关客户

这个动作将是在服务器端是与客户端的形式形式。

我(在运行时已知对我来说)为每个客户端,例如部分独特的标题

窗体标题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

我打电话ClientRemoveIdServerDisconnect程序

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

谁能告诉我有什么错吗?

+2

为什么不只是给'TMyContext'自己的关联窗口列表?当窗口打开时,将其添加到客户端的列表中。当窗口关闭时,将其从客户端列表中删除。当客户端断开连接时,通过列表关闭所有仍然打开的窗口。你应该**保持跟踪你的窗户,而不是**狩猎**。 –

回答

4

有相当多的事情错在这里:

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

如果我遇到了这个问题,我会用Screen.Forms[]解决。类似这样的:

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

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