0

I have a basic try..except to catch errors when trying to load a PNG file into a TImage:

try
  Previewimage.Picture.LoadFromFile(filename);
except
  //code to handle exception
end;

Normally this works fine if the file does not exist, or in my case the PNG is corrupted. I have no control over the source creation of the PNG, so need to catch when the PNG cannot be loaded, ie it gives the error:

This "Portable Network Graphics" image is not valid because it contains invalid pieces of data (crc error).

My issue is that the try..except is within a worker thread. This seems to cause the try..except to be ignored, and my program crashes with the CRC exception.

Are there any easy fixes for this issue?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Some1Else
  • 715
  • 11
  • 26
  • `TImage` is a visual component, meaning it has affinity to the main thread and cannot be manipulated from a background thread. – J... Dec 06 '21 at 21:27
  • It can and does happily update every time unless the PNG is corrupted. I understand threading and possible issues with multiple threads trying to update the display could cause issues, but this is strictly only ever a single thread. – Some1Else Dec 06 '21 at 21:28
  • 1
    No, it's not a single thread - not if you're calling this code from a thread other than the main thread (which you say you are). There is no way to make accessing a visual component threadsafe - the main thread could be trying to draw the image at the same time you're overwriting it in another thread, for example, and there are no in-built mechanisms to allow you to synchronize such access. It can appear to work, sure, but that doesn't mean it won't fail randomly later - if it works, it works by luck, not by design. – J... Dec 06 '21 at 21:33
  • 2
    As for the rest, we would need to see your actual code. What is your code doing in the `except` block? It should be trivial to supply a [mcve] here. `try/except` definitely works in threads so something else you're doing is causing it to fail. Most likely you're doing something in the `except` block that is itself throwing a second exception after catching the first. Consider installing and using a debugging tool like MadExcept. – J... Dec 06 '21 at 21:37
  • OK, then what is the best way to make that thread safe? How do I tell the main thread to try and load the PNG file outside of the calling thread? Also MadExcpet did point directly to the LoadFromFIle call giving the error I reported. – Some1Else Dec 06 '21 at 21:40
  • If you have exception details from MadExcept then you should include them in your question. Remy has given you a great answer below for how to actually solve your problem, but we still haven't addressed the problem that brought you here in the first place - we haven't addressed this because you still have not shown us your real code. – J... Dec 07 '21 at 14:15

1 Answers1

9

Exceptions and try..except blocks work just fine in worker threads. But accessing UI controls without proper synchronization can lead to all kinds of problems. So just don't do it.

In the context of the worker thread, load the PNG file using a local TPicture object, or better a TPNGImage object, then use TThread.Synchronize() or TThread.Notify() to Assign() that object to the TImage in the context of the main thread, eg:

try
  PNG := TPNGImage.Create;
  try
    PNG.LoadFromFile(filename);
    TThread.Synchronize(nil,
      procedure
      begin
        Previewimage.Picture.Assign(PNG);
      end
    );
  finally
    PNG.Free;
  end;
except
  //code to handle exception
end; 
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770