I have a simple program, single threaded, with a main form that has the controls, and another form with a bitmap and some TLabels on top of the bitmap that have the score, clock time, penalty time teams, and period.

In my main form, I have a TTimer with a 500ms interval that, when started, computes the clock and any penalty times as it counts down and updates the labels on the other form. The basic code in the timer event is:

  // decrement main clock
  if ClockEndTime > Now then
    begin
      MainClockTime := ClockEndTime - Now;
...
  else
    // clock time is expired
    begin
      MainClockTime := ZeroTime;
      tmrMainClock.Enabled := False;
      ClockRunning := False;
...
    end;
    // update the timer values and overlay
    lblClock.Caption := FormatDateTime('n:ss',MainClockTime);
    fOverlay.lblClock.Caption := lblClock.Caption;
...

After 1 to 2 hours, the main from will stop responding, and I get a "Canvas does not allow" exception. The form with the labels and the bitmap has a blank spot where the time clock should be.

Exception error

I have to close and restart the program for it to work again. None of the controls on the main form will respond even after I acknowledge the exception. It seems like the TTimer event might still be firing and having the same draw issues. I have a hotkey for another function that still works while the program appears to be frozen.

I tried an exception handler in the timer event around where I update the label captions. It never shows my message box, but appears that it is going to the exception handler as I added code to close the other form, wait some time, and then reopen it. The other form goes away and returns, but then nothing appears to draw on it. It shows what is in the background behind it.

Do you think it is an issue because my main form code is updating labels on the other form?

It is hard to test, as it involves waiting 1 to 2 hours for the issue to re-appear. I am wondering, has anyone experienced something like this?

I am using Delphi 10.4 Community Edition, and the program runs on Windows 11.

One more interesting thing I noted the last time I tested is that, while my program was trying to update the labels, it also caused a GIF image on a completely unrelated Delphi 7 program that I have running to move positions. I have no idea why one program would impact the other. The only thing they have in common is the use of a TTimer.

1

There are 1 answers

0
Craig On

The issue was a function I was using to get a pixel color from the screen. I called this function in my TTimer event.

function TfConfigureMute.GetPixelColor(X,Y: integer): TColor;
var
  dc: HDC;

begin
  // Get Device Context of windows desktop
  dc := GetDC(0);
  // Read the color of the pixel at the given coordinates
  Result := GetPixel(dc,X,Y);
  ReleaseDC(0,dc);
end;

I was originally missing the ReleaseDC(0,dc); line. So that was the leak.

Thanks for your time.