File Download With ProgressBar

Share your advanced PureBasic knowledge/code with the community.
Blankname
Enthusiast
Enthusiast
Posts: 120
Joined: Sun Oct 14, 2012 9:11 am

File Download With ProgressBar

Post by Blankname »

I was searching and came across a older thread to accomplish this. I felt like updating his code a bit to support the new and improved PB functions. I was able to strip a lot of messy code, and make it much more understandable. Plus now it will grab the file size regardless to header length.

Credits to V2 for writing the original source here http://www.purebasic.fr/english/viewtopic.php?t=8331.

Edit: Updated the code to thread the download, and you can stop the download process. Supports one simultaneous download without freezing up the form any.

Code: Select all

Global StopDownload.l = 0

Enumeration
  #Window 
  #Start
  #ProgressBar
  #Frame
  #Label
  #Label2
  #URL
EndEnumeration

Structure DownloadData
  Folder.s
  File.s
  URL.s
EndStructure

Procedure DoEvents()
  msg.MSG
  If PeekMessage_(msg, 0, 0, 0, 1)
    TranslateMessage_(msg)
    DispatchMessage_(msg)
  Else
    Delay(1)
  EndIf
EndProcedure

Procedure DownloadWithProgress(*Parameters.DownloadData)
  
  Protected.l FileBytes = 0, Bytes = 0, INTERNET_FLAG_RELOAD = $80000000, Size, Buffer = 4096, LastSize, Timer, Timed
  Protected.b isLoop = 1, OpenType = 1
  Protected.s Header, Line
  
  ;Get Filesize
  Header = GetHTTPHeader(*Parameters\URL)
  Repeat
    x + 1
    Line = StringField(Header, x, Chr(10))
  Until FindString(Line, "Content-Length:", 1, #PB_String_NoCase)
  Size = Val(StringField(Line, 2, "Content-Length: "))
  
  ;Allocate Buffer For File Data
  *Memory = AllocateMemory(Buffer)
  
  ;Create File To Dump Data To And Initialize WinINet
  Result = CreateFile(1, *Parameters\Folder + *Parameters\File)
  hInet = InternetOpen_("", OpenType, #Null, #Null, 0) 
  hURL = InternetOpenUrl_(hInet, *Parameters\URL, #Null, 0, INTERNET_FLAG_RELOAD, 0)
  
  If Size > 1048576
    SetGadgetText(#Label, "File Size: "+Str(Size/1048576)+" MB")
  ElseIf Size > 1024
    SetGadgetText(#Label, "File Size: "+Str(Size/1024)+" KB")
  Else
    SetGadgetText(#Label, "File Size: "+Str(Size)+" Bytes")
  EndIf
  SetGadgetAttribute(#ProgressBar, #PB_ProgressBar_Maximum, Size)
  
  ;Start Downloading
  Timer = ElapsedMilliseconds()
  Repeat 
    InternetReadFile_(hURL, *Memory, Buffer, @Bytes) 
    If Bytes = 0
      isLoop = 0
    Else
      FileBytes = FileBytes + Bytes
      Timed = ElapsedMilliseconds()-Timer
      If Timed > 1000
        SetGadgetText(#Label2, "Download Speed: "+Str((FileBytes - LastSize)/1024)+" KB/s")
        Timer = ElapsedMilliseconds()
        LastSize = FileBytes
      EndIf
      If Size >= FileBytes : SetGadgetState(#ProgressBar, FileBytes) : EndIf
      If StopDownload = 1 : isLoop = 0 : StopDownload = 0  : EndIf
      WriteData(1, *Memory, Bytes)
    EndIf
    DoEvents()
  Until isLoop = 0
  
  ;Release Handles
  InternetCloseHandle_(hURL)
  InternetCloseHandle_(hInet)
  CloseFile(1)
  
  ;Form Clean
  SetGadgetState(#ProgressBar, 0)
  SetGadgetText(#Label, "File Size: ")
  SetGadgetText(#Label2, "Download Speed: ")
  SetGadgetText(#Start, "Start")
  
  ;Clean Up
  FreeMemory(*Memory)
  ClearStructure(*Parameters, DownloadData)
  FreeMemory(*Parameters)
  
EndProcedure

InitNetwork()

If OpenWindow(#Window, 0, 0, 400, 175, "Download With Progress", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  StringGadget(#URL, 10, 10, 380, 20, "http://ddj9plya1d2mr.cloudfront.net/ubuntu-13.04-desktop-amd64.iso")
  ProgressBarGadget(#ProgressBar, 10, 40, 380, 30, 0, 100, #PB_ProgressBar_Smooth)
  TextGadget(#Label, 10, 80, 300, 20, "File Size:")
  TextGadget(#Label2, 10, 100, 300, 20, "Download Speed:")
  Frame3DGadget(#Frame, -10, 120, 420, 110, "")
  ButtonGadget(#Start, 280, 140, 110, 25, "Start", #PB_Button_Default)
  
  Repeat 
    EventID = WaitWindowEvent()
    Select EventID
        
      Case #PB_Event_Gadget
        Select EventGadget()
          Case #Start
            If IsThread(Thread)
              StopDownload = 1
            Else
              URL.s = GetGadgetText(#URL)
              ;Get Filename
              TrimURL.s = GetURLPart(URL, #PB_URL_Path)
              Position = CountString(TrimURL, "/") + 1
              File.s = StringField(TrimURL, Position, "/")
              ;Request Path
              Folder.s = PathRequester("Where do you want to save '"+File+"'?", "C:\")
              If Folder
                *Parameters.DownloadData = AllocateMemory(SizeOf(DownloadData))
                *Parameters\File = File
                *Parameters\Folder = Folder
                *Parameters\URL = URL
                Thread = CreateThread(@DownloadWithProgress(), *Parameters)
                SetGadgetText(#Start, "Cancel")
              EndIf
            EndIf
        EndSelect
        
      Case #PB_Event_CloseWindow
        End
        
    EndSelect
  ForEver
EndIf