一旦客户端与服务器断开连接,我将尝试关闭与客户端相关的所有表单
此操作将在服务器端进行。
例如,我为每个客户端都有(我在运行时已知的)部分唯一标题
表单标题 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
的调用完成之前完成。 - 您有关闭不属于您的进程的窗口的危险。
如果我遇到这个问题,我会使用 Screen.Forms[]
来解决它。像这样的事情:
for i := Screen.FormCount-1 downto 0 do
if CaptionMatches(Screen.Forms[i]) then
Screen.Forms[i].Close;
这只是一个大纲。我相信你能理解这个概念。关键点是不要使用EnumWindows
,而是使用VCL 自己的机制来枚举表单。
关于forms - Delphi - Indy关闭所有与客户相关的表单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37904188/