调用ShowMessage时会发生什么?

时间:2015-09-14 12:36:47

标签: delphi delphi-xe

我正在处理通过COM端口与另一台设备通信的项目。 对于传入数据,我使用VaComm1RXchar事件,在那里我将消息存储到数组中并增加msgIndex,它表示消息数。

然后我调用我使用此消息的函数。

在此函数内部是此超时周期,我等待此消息:

  while MsgIndex < 1 do
  begin
  stop := GetTickCount;
  if (stop - start)> timeout then
    begin

      MessageBox(0, 'Timeout komunikace !', 'Komunikace', MB_OK);
      exit(false);
    end;
    sleep(10);
  end;

对我来说奇怪的是,当它像上面那样,它总是以超时结束。但是,当我在此之前放置一个ShowMessage(&#39; Waiting&#39;)时,我会在那里工作,然后它正确地工作。

有谁知道是什么导致了这种情况,我该如何解决?提前谢谢!

2 个答案:

答案 0 :(得分:6)

我们可以推断VaComm1RXchar事件是一个同步事件,并且通过在循环中阻止您的程序,您正在阻止允许该事件执行的正常消息处理。

另一方面,显示模式对话框会将消息处理传递到该对话框,以便正确地处理消息队列和Rx事件并正常处理。

如果这也有效,你可以肯定是这种情况(请不要写这样的代码 - 它只是为了证明这一点):

while MsgIndex < 1 do begin
  stop := GetTickCount;
  if (stop - start)> timeout then begin    
    MessageBox(0, 'Timeout komunikace !', 'Komunikace', MB_OK);
    exit(false);
  end;
  Application.ProcessMessages; // service the message queue so that
  sleep(10);                   // your Rx event can be handled
end;

如果这里有一个教训,那就是需要在后台线程上完成RS-232通信。由于您发现的原因,大多数"some chars have been received"事件的所有实现都会导致可怕的代码。您的主线程需要可以自由处理已收到字符的消息,但同时,您必须有一些并行进程等待接收到的字符才能完成一个有说服力的指令。事件驱动程序中不存在合理的解决方案,以便在一个线程上同时管理用户界面通信端口。

例如,AsyncPro **等一组组件将此功能包装到使用同步事件的数据包中,但组件管理工作线程上的开始和结束字符串(或字节)检测。这将从主线程中删除一级轮询(即:当完整数据包到达时,您总是会收到一个事件,而不是部分数据包)。或者,您可以将通信工作移至自定义线程并自行管理。

在任何一种情况下,这只是部分解决方案,当然,因为您仍然不能坚持在需要等待com流量的同步事件处理程序中编写长程序方法。如果您的单个过程需要对多个comport指令的序列做出反应,则第二级轮询(即管理一系列完整指令)仍然需要抽取消息队列。您还需要考虑的是将长方法分解为更短的部分,每个部分都响应特定的设备消息。

或者,对于严重程序化的流程自动化,将工作移动到后台线程通常也是一个好主意。这样,工作线程可以在等待来自硬件的事件时阻止同步对象(或在繁忙循环中轮询状态更新)。一个线程可以管理低级别的comport流量,解析和中继这些命令或数据包,而另一个线程可以管理更高级别的进程,该进程正在处理构成更大进程的完整comport指令序列。主线程主要应该只负责在工作人员之间编组这些消息,而不是自己进行任何等待。

另请参阅:I do not understand what Application.ProcessMessages in Delphi is doing

** VAComm也可以支持这样的事情,我不知道。 API和文档不能从TMS for ASync32公开获取,因此您需要查阅当地文档。

答案 1 :(得分:0)

当对话框显示时,会发生模态消息循环。此消息循环更改了您的行为,表示您与设备的通信需要存在消息循环。

因此,您的解决方案是为消息队列提供服务。在循环中调用Application.ProcessMessages会这样做,但也会产生其他问题。就像让你的UI变得可重入一样。

在不了解您的计划的情况下,我无法就如何解决此问题提供更详细的建议。