7

I used this tutorial http://delphi.about.com/od/kbthread/a/thread-gui.htm to create a class that asynchronously downloads a file from the internet in another thread with a TDownLoadURL. I did this because I want to download a file without blocking the UI thread so the program doesn't become unresponsive during large downloads, the progress bar can update, etc.

I am having a problem because even though I have done the download in another thread (inheriting from TThread and doing the work in the Execute method) the GUI thread seems to be blocked and does not process messages until the download is finished. Here is the code for my class: http://codepad.org/nArfOPJK (it's just 99 lines, a simple class). I am executing it by this, in the event handler for a button click:

var
    frame: TTProgressFrame;
    dlt: TDownloadThread;
begin
    dlt := TDownloadThread.Create(True);
    dlt.SetFile('C:\ohayo.zip');
    dlt.SetURL('http://download.thinkbroadband.com/512MB.zip');
    dlt.SetFrame(frame);
    dlt.SetApp(Application);
    dlt.Start;

Note: The SetApp method was for when I was manually calling app.ProcessMessages from inside the UpdateDownloadProgress method of my class TDownloadThread. This would keep the GUI from being unresponsive, but it made the progress bar behave wierdly (the moving glowing light thing of aero's progress bar moving way too fast), so I removed it. I want to fix this properly, and if I have to call ProcessMessages there's really no point in multithreading it.

Can someone help me fix this problem? Thanks.

Kokonotsu
  • 189
  • 2
  • 9

1 Answers1

5

I now have the solution for you!

Calling TDownLoadURL.Execute (your call to dl.Execute in TDownloadThread) results in the action being transferred back into the main thread which is why your UI becomes unresponsive.

Instead you should call ExecuteTarget(nil) which performs no such machinations and works as you intend: the download runs on the worker thread.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • @David Looking at the code, what would make the main thread wait on the download thread? Like I said, `Start` doesn't return until the download is done. What's this about? – Kokonotsu Feb 19 '11 at 19:02
  • @David No, the download thread is all that you see in the code I posted. That's the entire project basically, except for the very small amount of code for the main form button handler, most of which is also posted in the question. – Kokonotsu Feb 19 '11 at 19:25
  • @David I have determined it is TDownLoadURL, because I changed my code to use CreateThread instead of TThread, so for some reason TDownLoadURL is causing the GUI thread to wait. – Kokonotsu Feb 19 '11 at 20:27
  • @Kokonotsu Yes, I've been debugging the code too. `TDownloadURL` is design to work by running the Execute method out of the main thread. It gets back there by calling `SendAppMessage`. – David Heffernan Feb 19 '11 at 20:38
  • @Kokonotsu I think I have the answer now!! Make sure you put back your call to `Synchronize` when calling `UpdateProgress`. – David Heffernan Feb 19 '11 at 20:46
  • @David could you give me an example of your code? `Synchronize` has always been there. – Kokonotsu Feb 19 '11 at 21:09
  • @Kokonotsu The only change you need to make from the code you uploaded when you asked your question is to change line 97 of DownloadThread.pas from `dl.Execute;` to `dl.ExecuteTarget(nil);`. – David Heffernan Feb 19 '11 at 21:13
  • @Kokonotsu The reason I mentioned `Synchronize` is that you had been experimenting with replacing it with `Queue` or removing it altogether. – David Heffernan Feb 19 '11 at 21:13
  • @David: Finally! That took care of it, thanks so much, you saved me from having to rewrite this with WinSock! – Kokonotsu Feb 19 '11 at 21:42