Recent

Author Topic: [SOLVED] Program freeze and get Marked as "Not responding" But is still running  (Read 8563 times)

varg300

  • New Member
  • *
  • Posts: 37
I've made a simple program that bulk-downloads pictures from a web site.
You choose a starting number and an ending number, and the program starts to download all the pictures in between.

I have a TMemo that displays the file name of downloaded files.
When the download starts, Image files are starting to appear in the folder and filenames is added to the TMemo.
But after a few seconds, the program freezes and Windows says that it's "Not Responding". The funny thing is that the program is still running, and continues to download files, as new files continues to appear in the folder.
After a few minutes when the download is complete (Depending on how many images you want to download of corse) The program "Loosens" and is no longer 'Not responding'

There's also a label on the form that is suposed to show the name of the file curently being downloaded, but this does not work.

This is the code that runs when i press the "Download" button:
Code: [Select]
function GetInetFile (const fileURL, FileName: String): boolean;

const   BufferSize = 1024;

var
  hSession, hURL: HInternet;
  Buffer: array[1..BufferSize] of Byte;
  BufferLen: DWORD;
  f: File;   sAppName: string;

begin
  result := false;
  sAppName := ExtractFileName(Application.ExeName) ;
  hSession := InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0) ;

  try
    hURL := InternetOpenURL(hSession, PChar(fileURL), nil, 0, 0, 0) ;
    try
      AssignFile(f, FileName) ;
      Rewrite(f,1) ;

      repeat
        InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen) ;
        BlockWrite(f, Buffer, BufferLen)
      until BufferLen = 0;
        CloseFile(f) ;

        if FileSize(lokalfil) < 1500 then begin
          DeleteFile(lokalfil);
             end else  result := True;

    finally    InternetCloseHandle(hURL)
    end
  finally   InternetCloseHandle(hSession)
  end
end;



Procedure finnfil;
begin

  if undermapper=TRUE then begin
   temp:=IntToStr(nummer);

  if nummer < 1000 then mappe:=('/0/') ;
     if nummer >= 1000 then begin
       if nummer < 10000 then begin
        delete (temp,2,3);
       mappe:= ('/' +temp +'/');
     end;
   if nummer >= 10000 then begin
     delete (temp,3,3);
     mappe:= ('/' +temp +'/');
   end;


  end;

  webfil:= (adresse +mappe +(IntToStr(nummer)) +filtype[s]);
   lokalfil:=(IntToStr(nummer) +filtype[s]);
  end;

  if undermapper=FALSE then begin
    webfil:= (adresse +(IntToStr(nummer)) +filtype[s]);
   lokalfil:=(IntToStr(nummer) +filtype[s]);
  end;


end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  teljar:=8;
  start:=StrToInt(min.Text);
  stopp:=StrToInt(maks.Text);

  GroupBox1.Enabled:=FALSE;
  Button1.Enabled:=FALSE;
  min.Enabled:=FALSE;
  maks.Enabled:=FALSE;

  Memo1.Lines.Add('Starter nedlasting');
  Memo1.Lines.Add('av ' +IntToStr(stopp-start+1) +' Bilder');

       for nummer:=start to stopp DO begin
           teljar:=teljar+1;

           for s:=1 to filtyper DO begin

              finnfil;
               { showmessage ('Webfil: ' +webfil);
                showmessage ('Lokalfil: ' +lokalfil); }

                if not FileExists (lokalfil) then begin
                 Label1.Caption:=('Prøver ' +IntToStr(nummer));
               if GetInetFile(webfil, lokalfil) then begin
                 Memo1.Lines.Add(IntToStr(nummer) +filtype[s] +'  OK!');
                  break;
                    end;

                 end;
               end;
           end;

       GroupBox1.Enabled:=TRUE;
       Button1.Enabled:=TRUE;
         min.Enabled:=TRUE;
          maks.Enabled:=TRUE;
       Label1.Caption:=('Ferdig!');
       ShowMessage ('Ferdig!');
end;                               
As you can see, there's more variables and they are of corse Identified elsewhere

I have wery little knowledge of multi-threading, but i was just thinking that the problem might be that this is a single-threaded aplication? Or am i wrong...?

Is there an easy fix to this freezing problem?  :)
« Last Edit: July 28, 2012, 12:39:12 pm by varg300 »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12429
  • Debugger - SynEdit - and more
    • wiki
You need to call
Code: [Select]
  Application.ProcessMessages;on a regular base (at least a few times per second)

You can do that in the repeat until loop reading the image.

But: It also means the button on the form will be responsive, and you can click it again, while it is still running

Code: [Select]
button.enabled:=False;
« Last Edit: July 27, 2012, 10:35:27 pm by Martin_fr »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8836
  • Programming + Glam Metal + Tae Kwon Do = Me
I'll use threads for such a case, Application.ProcessMessages might work as well, but not as smooth as threads in my experience.

varg300

  • New Member
  • *
  • Posts: 37
Okay, i'll try that. Thanks!
I've made it so the button (Button1) gets disabled until the loop is finished, but are you saying that Application.ProcessMessages wil re-enable it?

What does Application.ProcessMessages actually do, just being curious here.

And about threads, is it much work to implement this?
This will make the program download the files "on the side" while the main form is still being idle and respond to input (Like a cancel or pause button) right?

Leledumbo

  • Hero Member
  • *****
  • Posts: 8836
  • Programming + Glam Metal + Tae Kwon Do = Me
Quote
but are you saying that Application.ProcessMessages wil re-enable it?
It won't, it's your responsibility to do it.
Quote
What does Application.ProcessMessages actually do, just being curious here.
In an event driven application, everything happens based on messages. A button click, a request of paint, keyboard press, etc. Sometimes, a message can't be instantly processed. Therefore a concept of message queue exists. While an application is still processing a message, other messages can still come and will be queued. Application.ProcessMessages forces the application to stop doing other things and process all messages in the queue before continuing its job.
Quote
And about threads, is it much work to implement this?
When you already get it, it shouldn't be too hard. But if not, you might face some concurrency problems. Therefore if you're willing to do it, I suggest to read the wiki article as deep as you can. Especially regarding resource sharing and Synchronize method.
Quote
This will make the program download the files "on the side" while the main form is still being idle and respond to input (Like a cancel or pause button) right?
Yep

varg300

  • New Member
  • *
  • Posts: 37
Okay thank you for the info   ;)
Got it Working with  Application.ProcessMessages;

Next time i wil try to use threads and see if i can get it to work that way, so off to the wiki and do some research i go hehe.

By the way, i have a Timage that shows the last downloaded image file, the code filters out and displays JPG files only, as i understand that Timage does not support all formats.
The only problem is that it seems like some of the JPG's (1 of 500 perhaps...)
cannot be read by Timage, and the program crashes. I've read that JPG2000 is not supported, is this correct?
Are there any way to trap and ignore this error to keep the program from crashing?

EDIT: Think i got it working by executing Timage.Picture.LoadFromFile in a Try/Except clause
« Last Edit: July 28, 2012, 12:38:56 pm by varg300 »

Elmug

  • Hero Member
  • *****
  • Posts: 849
If the purpose is to download images, I would not show them while the downloading is taking place. That can be bottle-necking things.

That would also help for the program crashing when an image is not supported.

After download, another app can be used to check them, and would use Try to make sure that app does not crash, but raises exeption, and writes a file listing incompatible images.

I also think that your program is not really freezing, but "not responding" means that it can not take input at that point, waiting for external activity, likely from the images being served, specially since you say that it comes back after a while.
« Last Edit: July 28, 2012, 01:50:38 pm by Elmug »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8836
  • Programming + Glam Metal + Tae Kwon Do = Me
Quote
I've read that JPG2000 is not supported, is this correct?
It seems lo, at least in my last checkout (just now, FPC 2.7.1 r21977, Lazarus 1.1 r38071).

 

TinyPortal © 2005-2018