调用 ShowMessage 时会发生什么?

What happens when ShowMessage is called?

我正在从事通过 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;

对我来说奇怪的是,当像上面这样时,它总是以超时结束。但是当我在此之前放在那里时 while cycle a ShowMessage('Waiting') 然后它工作正确。

有谁知道是什么原因造成的,我该如何解决?提前致谢!

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

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

在不了解你的程序的情况下,我无法就你应该如何解决这个问题提供更详细的建议。

我们可以推断出 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**,例如,将此功能包装到使用同步事件的数据包中,但这些组件在工作线程。这从主线程中删除了一个级别的轮询(即:当完整的数据包到达时,您总是会收到一个事件,而不是部分数据包)。或者,您可以将通信工作移至自定义线程并自行管理。

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

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

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


** VAComm也可能支持这样的东西,我不知道。 API 和文档未从 TMS for ASync32 公开提供,因此您需要查阅本地文档。