Page 1 of 1

Windows - Downloader with progress and status

Posted: Wed Mar 07, 2007 10:02 am
by Joakim Christiansen
I put together some code and made this, it's a threaded downloader which also displays the download speed.
This is just meant as an example to learn from!
Feel free to improve it or fix any bugs! :wink:

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;Downloader with progress and status;;
;;By Joakim L. Christiansen          ;;
;;Version 1.1                        ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

EnableExplicit

Global DownloadURL$, DownloadFilename$, StopDownload, IsDownloading

#Main = 0 ;Window
Enumeration ;Gadgets
  #Text
  #Download
  #URL
  #Progress
EndEnumeration

Procedure DownloadFile(Dummy)
  Protected hInet, hURL, Bytes
  Protected BufferLength = 2048, Buffer$ = Space(BufferLength)
  
  Protected Url$      = DownloadURL$
  Protected Filename$ = DownloadFilename$
  Protected File
  Protected CurrentSize, PreviousSize, FileSize, Time, BytesPerSecond
  Protected Domain$, String$, i, BufferLengthWas = BufferLength
  Protected hInetCon, hHttpOpenRequest, iretval
  
  hInet = InternetOpen_("Downloader",0,0,0,0)
  hURL  = InternetOpenUrl_(hInet,Url$,0,0,$80000000,0)
  
  ;Get filesize
  Domain$  = StringField(Url$,3,"/")
  hInetCon = InternetConnect_(hInet,Domain$,80,#Null,#Null,3,0,0)
  If hInetCon
    hHttpOpenRequest = HttpOpenRequest_(hInetCon,"HEAD",ReplaceString(Url$,"http://"+Domain$+"/",""),#Null,#Null,0,$80000000,0)
    If hHttpOpenRequest
      iretval = HttpSendRequest_(hHttpOpenRequest,#Null,0,0,0)
      If iretval
        HttpQueryInfo_(hHttpOpenRequest,19,@Buffer$,@BufferLength,0) ;changes the buffer length
        String$ = PeekS(@Buffer$,BufferLength): BufferLength = BufferLengthWas
        If Trim(String$) = "200"
          HttpQueryInfo_(hHttpOpenRequest,22,@Buffer$,@BufferLength,0)
          String$ = PeekS(@Buffer$,BufferLength): BufferLength = BufferLengthWas
          If FindString(String$,"Content-Length:",1)
            i = FindString(String$,"Content-Length:",1) + Len("Content-Length:")
            String$ = Mid(String$,i,Len(String$)-i)
            FileSize = Val(Trim(String$))
          EndIf
        EndIf
      EndIf
    EndIf
  EndIf
  
  ;Download file and update status
  If hURL
    File = CreateFile(#PB_Any,Filename$)
    If File
      Time = ElapsedMilliseconds()
      SetGadgetAttribute(#Progress,#PB_ProgressBar_Maximum,FileSize)
      While InternetReadFile_(hURL,@Buffer$,BufferLength,@Bytes) And Bytes > 0
        If StopDownload
          Break
        EndIf
        WriteData(File,@Buffer$,Bytes)
        ;File + PeekS(@Buffer,Bytes)
        CurrentSize + Bytes
        SetGadgetState(#Progress,CurrentSize)
        SetGadgetText(#Text,Str(CurrentSize/1024)+"/"+Str(FileSize/1024)+"kb - "+Str(BytesPerSecond/1024)+"kb/s")
        If Time < ElapsedMilliseconds() - 1000
          Time = ElapsedMilliseconds()
          BytesPerSecond = CurrentSize - PreviousSize
          PreviousSize = CurrentSize
        EndIf
      Wend
      CloseFile(File)
    Else
      MessageRequester("Warning!","Error creating file!",#MB_ICONWARNING)
    EndIf
    ;Reset status
    StopDownload = #False
    IsDownloading = #False
    SetGadgetText(#Text,"0/0kb - 0kb/s")
    SetGadgetState(#Progress,0)
    SetGadgetText(#Download,"Download")
    ;If file is incomplete then delete it
    If CurrentSize < FileSize
      DeleteFile(Filename$)
    Else
      MessageRequester("Info","Download complete!",#MB_ICONINFORMATION)
    EndIf
  Else
    MessageRequester("Warning!","Download failed!",#MB_ICONWARNING)
  EndIf
  
  InternetCloseHandle_(hURL)
  InternetCloseHandle_(hInetCon)
  InternetCloseHandle_(hInet)
EndProcedure

If OpenWindow(#Main,0,0,300,70,"Downloader with progress and status",#PB_Window_SystemMenu|#PB_Window_ScreenCentered) And CreateGadgetList(WindowID(#Main))
  StringGadget(#URL,5,5,225,20,"http://www.mannindustries.net/soldat/soldat131.zip"): ButtonGadget(#Download,235,5,60,20,"Download")
  ProgressBarGadget(#Progress,5,30,290,20,0,100)
  TextGadget(#Text,5,54,290,20,"0/0kb - 0kb/s",#PB_Text_Center)
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        StopDownload = #True
        Delay(20)
        Break
      Case #PB_Event_Gadget
        Select EventGadget()
          Case #Download
            If Not IsDownloading
              DownloadURL$      = GetGadgetText(#URL)
              DownloadFilename$ = SaveFileRequester("Save as",StringField(DownloadURL$,CountString(DownloadURL$,"/")+1,"/"),"*.*",0)
              If DownloadURL$ And DownloadFilename$
                CreateThread(@DownloadFile(),0)
                SetGadgetText(#Download,"Stop")
                IsDownloading = #True
              EndIf
            Else
              StopDownload = #True
              IsDownloading = #False
              SetGadgetState(#Progress,0)
              SetGadgetText(#Download,"Download")
            EndIf
        EndSelect
    EndSelect
  ForEver
Else
  MessageRequester("Warning!","Error opening window!",#MB_ICONWARNING)
EndIf

Posted: Wed Mar 07, 2007 11:37 am
by gnozal
Thanks.
I would change

Code: Select all

hInet = InternetOpen_("Downloader",1,0,0,0)
to

Code: Select all

#INTERNET_OPEN_TYPE_PRECONFIG = 0 ; use registry configuration
#INTERNET_OPEN_TYPE_DIRECT = 1 ; direct to net
hInet = InternetOpen_("Downloader",#INTERNET_OPEN_TYPE_PRECONFIG,0,0,0) 
so it would also work with a proxy.

Posted: Wed Mar 07, 2007 2:06 pm
by utopiomania
Thanks, it works fine. I made some slight alterations to its logic though because the demo has to be restarted in order
to download more than once.

Code: Select all

Global IsDownloading
.
.
  SetGadgetState(#Progress,0) 
  SetGadgetText(#Download,"Download") 
  IsDownloading = #False 
EndProcedure
.
.
            Else 
              StopDownload = #True 
            EndIf 

Posted: Wed Mar 07, 2007 2:14 pm
by Joakim Christiansen
Okay, added both suggestions.

Posted: Mon May 21, 2007 7:10 pm
by Trond
Does anyone know how to get the filename before downloading?

Posted: Sun Jul 01, 2007 12:07 pm
by Trond
Which flags make up $80000000?

Posted: Sun Jul 01, 2007 12:18 pm
by netmaestro
#INTERNET_FLAG_RELOAD = $80000000

Posted: Mon Jul 09, 2007 3:15 pm
by Karbon
Has anyone noticed that if you put this on it's own window that closewindow() won't close the download window? I'm assuming it's a thread issue of some sort and unfortunately one of my userlibs isn't threadsafe so compiling with /THREAD isn't working for me right now.

Posted: Tue Jul 10, 2007 3:30 am
by pdwyer
I notice that lots of people are using winAPI for this kind of thing rather than PB network functions. Is there are reason for that? (or is it just to learn the winAPI method?)

Connection = OpenNetworkConnection(ServerName$, Port [, Mode])

I'm just wondering if I should avoid the PB built in functions to do things like this for any reason

I haven't really played with the PB network stuff much but are there features missing? A quick look shows that the timouts might be hard to set...

Thanks

Posted: Tue Jul 10, 2007 2:21 pm
by Karbon
Well, it's all pretty much the same on Windows I guess :-)

Posted: Thu Aug 09, 2007 9:52 pm
by Trond
It it possible to set a timeout?