对于某些特定需求,我需要创建在dll中等待套接字请求(或回答)的过程:
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
......
procedure MyWaitProc; stdcall;
begin
Go := false;
while not Go do
begin
// Wating...
// Application.ProcessMessages; // Works with this line
end;
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
MessageBoxA(0, PAnsiChar('Received: '+Socket.ReceiveText), '', MB_OK);
Go := true;
end;
exports
MyWaitProc;
当我呼叫Application.ProcessMessages
时,一切正常:应用程序等待请求然后继续。但在我的情况下,调用Application.ProcessMessages
会导致在主机应用程序上解锁主窗体(而不是dll的一个)。当我不打电话给Application.ProcessMessages
应用程序时,只是挂起它无法处理消息......
那么,如何创建这样一个套接字答案的程序呢?
也许有一种方法可以在不使用Application.ProcessMessages
的情况下等待套接字答案?
修改
我也试过使用TIdTCPServer,由于某些原因,结果是一样的。
TForm1 = class(TForm)
IdTCPServer1: TIdTCPServer;
.....
procedure MyWaitProc; stdcall;
begin
Go := false;
while not Go do
begin
// Waiting ...
// Application.ProcessMessages;
end;
end;
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
s: string;
begin
s := AContext.Connection.Socket.ReadString(1);
AllText := AllText + s;
Go := True;
end;
答案 0 :(得分:4)
TServerSocket
以非阻塞模式运行,这取决于处理窗口消息。要删除该依赖性,您必须将其切换为阻止模式。
TIdTCPServer
专门以阻塞模式运行,因此没有窗口消息。如果您遇到问题,那么您就是在滥用它。例如,在您的TServerSocket
代码中,在收到回复之前,您不会设置Go = True
,而是在您的TServerSocket
代码中设置Go = True
,然后才能阅读回复代替。
作为替代方案,请查看Indy的TIdSimpleServer
组件。 TIdSimpleServer
是同步的,一次只接受1个连接,而TIdTCPServer
是异步的,一次接受多个连接。例如:
TForm1 = class(TForm)
ServerSocket: TIdSimpleServer;
procedure MyWaitProc; stdcall;
var
s: String;
begin
ServerSocket.Listen;
s := ServerSocket.IOHandler.ReadLn;
ServerSocket.Disconnect;
MessageBox(0, PChar('Received: '+s), '', MB_OK);
end;
exports
MyWaitProc;
答案 1 :(得分:1)
不是创建偶尔调用Application.ProcessMessages
的循环,而是可以创建TThread
的后代并将套接字请求移动到TThread.Execute
方法。使用TThread.OnTerminate在线程完成其工作时通知您的表单(或任何其他类)。
sample code提供了有关如何使用TThread
的详细信息。
还有其他几个3rd party线程库比TThread
提供更多的灵活性或更易于使用,如果您不熟悉多个TThread
,我强烈推荐其中任何一个-threading。
注意:使用Application.ProcessMessages
时有一些严重side-effects。您正在使用dll解锁应用程序的mainform,在代码中看到其中一个。它打破了VCL构建的单线程UI模型。 ProcessMessages
有它的位置,但使用线程更适合你所描述的情况。
var Slowpoke: TMyLongRunningProcessThread;
procedure MyWaitProc(Completed:TNotifyEvent)
begin
Slowpoke := TMyLongRunningProcessThread.Create(True);
Slowpoke.FreeOnTerminate := True;
Slowpoke.OnTerminate := Completed;
Slowpoke.Resume;
end;
启动线程后, MyWaitProc
会立即返回,因此GUI可以自由响应用户操作。当线程终止时,它调用Completed
指向的事件处理程序。
显然,如果您需要从线程中检索数据,您需要让线程在释放自身之前将其写入可访问的内存位置,或者删除FreeOnTerminate
以便可以从线程中检索数据财产。