Search code examples
delphidelphi-2009vcl

Application.ProcessMessages hangs?


my single threaded delphi 2009 app (not quite yet complete) has started to have a problem with Application.ProcessMessages hanging. my app has a TTimer object that fires every 100 ms to poll an external device. i use Application.ProcessMessages to update the screen when something changes so the app is still responsive.

one of these was in a grid OnMouseDown event. in there, it had an Application.ProcessMessages that essentially hung. removing that was no problem except that i soon discovered another Application.ProcessMessages that was also blocking.

i think what may be happening to me is that the TTimer is--in the app mode i'm currently debugging--probably taking too long to complete. i have prevented the TTimer.OnTimer event hander from re-entering the same code (see below):

procedure TfrmMeas.tmrCheckTimer(Sender: TObject);
begin
  if m_CheckTimerBusy then
    exit;

  m_CheckTimerBusy:=true;
  try
    PollForAndShowMeasurements;
  finally
    m_CheckTimerBusy:=false;
  end;
end;

what places would it be a bad practice to call Application.ProcessMessages? OnPaint routines springs to mind as something that wouldn't make sense.

any general recommendations?

i am surprised to see this kind of problem arise at this point in the development!


Solution

  • thank you all for your comments/suggestions.

    here i made a test app that has a timer routine that takes longer than the interval it is set for. when i push button1, Application.ProcessMessages hangs. my solution for now is to disable the timer during the timer routine.

    later we plan to put the "device communications" in a thread.

    thank you! mp

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, ExtCtrls, StdCtrls;
    
    type
      TForm1 = class(TForm)
        Timer1: TTimer;
        Button1: TButton;
        Memo1: TMemo;
        procedure Timer1Timer(Sender: TObject);
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      memo1.Lines.Add('text 1');
    
      // this call blocks
      Application.ProcessMessages;
    
      memo1.Lines.Add('text 2');
    end;
    
    procedure TForm1.Timer1Timer(Sender: TObject);
    var
      iTime:cardinal;
    begin
      // fix by adding this:  timer1.Enabled:=false;
    
      iTime:=GetTickCount;
      while GetTickCount-iTime<200 do
        ;
    
      // fix by adding this:  timer1.Enabled:=true;
    end;
    
    end.
    
    object Form1: TForm1
      Left = 0
      Top = 0
      Caption = 'Form1'
      ClientHeight = 286
      ClientWidth = 426
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Tahoma'
      Font.Style = []
      OldCreateOrder = False
      PixelsPerInch = 96
      TextHeight = 13
      object Button1: TButton
        Left = 8
        Top = 56
        Width = 75
        Height = 25
        Caption = 'Button1'
        TabOrder = 0
        OnClick = Button1Click
      end
      object Memo1: TMemo
        Left = 112
        Top = 8
        Width = 297
        Height = 233
        Lines.Strings = (
          'Memo1')
        TabOrder = 1
      end
      object Timer1: TTimer
        Interval = 100
        OnTimer = Timer1Timer
        Left = 200
        Top = 144
      end