1

对于某些特定需求,我需要在 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;
4

2 回答 2

4

TServerSocket默认情况下以非阻塞模式运行,这取决于处理窗口消息。要消除这种依赖关系,您必须将其切换到阻塞模式。

TIdTCPServer仅在阻塞模式下运行,因此没有窗口消息。如果你对它有问题,那么你就是在滥用它。例如,在您的TServerSocket代码中,您Go = True在收到响应后才进行设置,但在您的TServerSocket代码中,您Go = True在读取响应之前进行设置。

作为替代方案,请查看 Indy 的TIdSimpleServer组件。 TIdSimpleServer是同步的,一次只接受一个连接,而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; 
于 2012-07-02T19:57:11.973 回答
1

而不是创建一个偶尔调用的循环,Application.ProcessMessages您可以创建一个后代TThread并将套接字请求移动到该TThread.Execute方法。当线程完成其工作时,使用 TThread.OnTerminate 通知您的表单(或任何其他类)。

示例代码提供了有关如何使用的更多详细信息TThread

还有其他几个3rd 方线程库,它们要么提供更大的灵活性,要么更容易使用,如果您不熟悉多线程TThread,我强烈推荐其中任何一个。TThread

注意使用Application.ProcessMessages. 您在代码中看到其中之一,其中 dll 解锁了应用程序的主窗体。它打破了 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以便可以通过属性从线程中检索数据。

于 2012-07-02T13:51:51.830 回答