Windows - Downloader with progress and status

Share your advanced PureBasic knowledge/code with the community.
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Windows - Downloader with progress and status

Post 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
Last edited by Joakim Christiansen on Wed Mar 07, 2007 2:14 pm, edited 1 time in total.
I like logic, hence I dislike humans but love computers.
gnozal
PureBasic Expert
PureBasic Expert
Posts: 4229
Joined: Sat Apr 26, 2003 8:27 am
Location: Strasbourg / France
Contact:

Post 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.
For free libraries and tools, visit my web site (also home of jaPBe V3 and PureFORM).
User avatar
utopiomania
Addict
Addict
Posts: 1655
Joined: Tue May 10, 2005 10:00 pm
Location: Norway

Post 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 
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Post by Joakim Christiansen »

Okay, added both suggestions.
I like logic, hence I dislike humans but love computers.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Does anyone know how to get the filename before downloading?
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Which flags make up $80000000?
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

#INTERNET_FLAG_RELOAD = $80000000
BERESHEIT
Karbon
PureBasic Expert
PureBasic Expert
Posts: 2010
Joined: Mon Jun 02, 2003 1:42 am
Location: Ashland, KY
Contact:

Post 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.
-Mitchell
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post 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
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
Karbon
PureBasic Expert
PureBasic Expert
Posts: 2010
Joined: Mon Jun 02, 2003 1:42 am
Location: Ashland, KY
Contact:

Post by Karbon »

Well, it's all pretty much the same on Windows I guess :-)
-Mitchell
Check out kBilling for all your billing software needs!
http://www.k-billing.com
Code Signing / Authenticode Certificates (Get rid of those Unknown Publisher warnings!)
http://codesigning.ksoftware.net
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

It it possible to set a timeout?
Post Reply