Results 1 to 7 of 7

Thread: Download structure fails

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Question Download structure fails

    Hello all.

    I am totally into structures at this point, mostly because of their simplicity in use.

    I am now working on a "download structure", which allows you to download and keep track on a file.

    This is the code:
    Code:
      Public Structure FileDownload
            Sub New(ByVal URL As String, ByVal DestFilePath As String)
                Me.URL = URL
                Me._percent = 0
                Me.DownloadSize = Net.WebRequest.Create(Me.URL).GetResponse.ContentLength
                Me.DownloadedSize = 0
                Me.Percent = 0
                Me.DestinationFile = DestFilePath
                Me.client = New Net.WebClient
            End Sub
            Sub StartDownload()
                client.DownloadFileAsync(New Uri(Me.URL), Me.DestinationFile)
            End Sub
            Sub StopDownload(ByVal DeleteFile As Boolean)
                On Error Resume Next
                Me.client.CancelAsync()
                If DeleteFile = True And System.IO.File.Exists(Me.DestinationFile) Then
                    SetAttr(Me.DestinationFile, FileAttribute.Normal)
                    System.IO.File.Delete(Me.DestinationFile)
                    Me.DownloadedSize = 0
                End If
                Me.Percent = 0
            End Sub
            Private _percent As Single
            Public Property Percent() As Single
                Get
                    If System.IO.File.Exists(Me.DestinationFile) And Me.DownloadSize <> 0 Then
                        Me._percent = Me.DownloadedSize * 100 / Me.DownloadSize
                    Else
                        Me._percent = 0
                    End If
                    Return Me._percent
                End Get
                Set(ByVal value As Single)
                    Me._percent = value
                End Set
            End Property
            Private _DownloadedSize As Long
            Public Property DownloadedSize() As Long
                Get
                    Try
                        Me._DownloadedSize = New System.IO.FileInfo(Me.DestinationFile).Length
                    Catch
                        Me._DownloadedSize = 0
                    End Try
                    Return Me._DownloadedSize
                End Get
                Set(ByVal value As Long)
                    Me._DownloadedSize = value
                End Set
            End Property
            Private client As Net.WebClient
            Public DestinationFile As String
            Public URL As String
            Public DownloadSize As Long
        End Structure
    It all seems to work fine using the following thread to download a file:
    Code:
    d = New FileDownload("http://www.myurl.com/url/to/download.exe", My.Computer.FileSystem.SpecialDirectories.Desktop & "\download.exe")      
    d.StartDownload()     
    Do While d.DownloadedSize < d.DownloadSize
             ProgressbarAdapter(d.Percent, d.DownloadedSize & "/" & d.DownloadSize & " (" & d.Percent & "&#37;)")
             Threading.Thread.Sleep(200) 
    Loop
    Now my big problem:
    The second time I download the file, the file is made but the downloaded bytes stay 0. I carefully delete the file and then start it again. Somehow it can't download the file, but no error is given. Only after a while it crashes.
    If I then restart it, it just downloads the file.

    Soo...what is the reason I can't download the same file to the same location twice while the program is running?

    This is really a weird bug

    EDIT:

    It ALWAYS happens when twice downloading the same file. Changing the output file won't solve it. Really need help at this point.
    Last edited by bergerkiller; May 25th, 2010 at 02:12 PM.

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: Download structure fails

    The first thing you need to do is to get rid of that On Error Resume Next and never use it again. If you believe that an exception can reasonably be thrown in your code then use a Try...Catch block to catch that exception specifically.

    Secondly, I would suggest that that type should be a class rather than a structure. Look at the .NET Framework and the types it contains and consider what's a class and what's a structure. Any type with as much functionality as yours would be a class.

    Once you've made those changes, your issue will probably either go away or you'll have a better idea of exactly what the cause is.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3

    Re: Download structure fails

    You can look in my signature for a Download Managing System and use it/borrow code from it.

  4. #4

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Download structure fails

    Yes I know of the error resume next, thats why I only use it when I have multiple commands that HAVE to be executed. If I put it all in one try block, and the first delete command fails, it doesnt continue wit hthe other stuff.

    Just a way to prevent placing every command in a try block

    Andd...I just found out it isn't related to my structure.
    I made a download thread without my structure (using a webclient), and it fails the second time I start.

    I think the webclient can only download a file once...

    Any other suggestions to download files?

  5. #5

    Re: Download structure fails

    Did you look in my signature?

  6. #6
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: Download structure fails

    On Error Resume Next simply ignores errors and continues. If you ignore an error, how do you expect to fix it? Use proper error handling and, when you catch an exception, you can diagnose the problem and fix it. While debugging at least, no error handling at all is better than On Error Resume Next.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  7. #7

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Download structure fails

    I fixed all problems already. It wasn't faulty error handling, I forgot to close a "getresponse" reader, causing the current stream to remain active. Trying to get the response from an active stream is impossible, causing a time-out.

    This was the line causing the trouble:
    Me.DownloadSize = Net.WebRequest.Create(Me.URL).GetResponse.ContentLength
    The response was embedded, so it was impossible to close it. I had to give the response his own variable and close that.


    I changed my structure to a class, for everyone interested, here is my (awesome) DownloadManager class for all your download needs

    Code:
    Public Class DownloadManager
    
        Sub New(ByVal URL As String, ByVal DestPath As String)
            Me.URL = URL
            Me.DestFileName = DestPath
        End Sub
        Public URL As String = ""
        Private dfln As String = ""
        Private Paused As Boolean = False
        Private Downloading As Boolean = False
        Private dledsize As Long = 0
        Private tldlsize As Long = 0
        Private dlfin As Boolean = False
        Private etime As Long
        Private ta As New Stopwatch
        Private stopdl As Boolean = False
    
        Public ReadOnly Property HasFinished() As Boolean
            Get
                Return dlfin
            End Get
        End Property
        Public Property DestFileName() As String
            Get
                Return dfln
            End Get
            Set(ByVal value As String)
                If Me.Downloading = False Then dfln = value
            End Set
        End Property
        Public ReadOnly Property IsDownloading() As Boolean
            Get
                Return Downloading
            End Get
        End Property
        Public ReadOnly Property IsPaused() As Boolean
            Get
                Return Paused
            End Get
        End Property
        Public ReadOnly Property DownloadedSize() As SizeMeasure
            Get
                Return New SizeMeasure(dledsize)
            End Get
        End Property
        Public ReadOnly Property TotalDownloadSize() As SizeMeasure
            Get
                If tldlsize = 0 Then
                    Dim ws As Net.WebResponse = Net.WebRequest.Create(Me.URL).GetResponse
                    Me.tldlsize = ws.ContentLength
                    ws.Close()
                End If
                Return New SizeMeasure(tldlsize)
            End Get
        End Property
        Public ReadOnly Property Percentage() As Single
            Get
                If Me.tldlsize > 0 Then
                    Dim ti As Integer = dledsize * 1000 / tldlsize
                    Return ti / 10
                Else
                    Return 0
                End If
            End Get
        End Property
        Public ReadOnly Property DownloadSpeed() As SpeedMeasure
            Get
                If etime <> 0 And Me.Downloading = True And Me.Paused = False Then
                    Return New SpeedMeasure(dledsize * 1000 / etime)
                Else
                    Return New SpeedMeasure(0)
                End If
            End Get
        End Property
        Public ReadOnly Property ElapsedTime() As TimeMeasure
            Get
                Return New TimeMeasure(etime)
            End Get
        End Property
        Public ReadOnly Property RemainingTime() As TimeMeasure
            Get
                If Me.Paused = False And Me.Downloading = True Then
                    Dim remainingbytes As Long = Me.tldlsize - Me.dledsize
                    Dim speed As Long = DownloadSpeed.BAS
                    If speed = 0 Then speed = 1
                    Return New TimeMeasure(remainingbytes * 1000 / speed)
                Else
                    Return New TimeMeasure(0)
                End If
            End Get
        End Property
        Public Structure TimeMeasure
            Sub New(ByVal Msecs As Long)
                LoadTime(Msecs)
            End Sub
            Public Sub LoadTime(ByVal MiliSeconds As Long)
                If MiliSeconds < 0 Then MiliSeconds = 0
                Me.TotalMiliSeconds = MiliSeconds
                Me.Hours = Int(MiliSeconds / 3600000)
                Me.Minutes = Int(MiliSeconds / 60000) - Me.Hours * 3600
                Me.Seconds = Int(MiliSeconds / 1000) - Me.Minutes * 60 - Me.Hours * 3600
                Dim hstr As String = Me.Hours
                Dim mstr As String = Me.Minutes
                Dim sstr As String = Me.Seconds
                If hstr.Length = 1 Then hstr = "0" & hstr
                If mstr.Length = 1 Then mstr = "0" & mstr
                If sstr.Length = 1 Then sstr = "0" & sstr
                Me.TimeStringHMS = hstr & ":" & mstr & ":" & sstr
                If Me.Hours > 0 Then
                    Me.TimeStringS = Int(MiliSeconds / 360000) & " hours"
                ElseIf Me.Minutes > 0 Then
                    Me.TimeStringS = Int(MiliSeconds / 60000) & " minutes"
                Else
                    Me.TimeStringS = Int(MiliSeconds / 1000) & " seconds"
                End If
            End Sub
            Public TimeStringHMS As String
            Public TimeStringS As String
            Public TotalMiliSeconds As Long
            Public Seconds As Long
            Public Minutes As Long
            Public Hours As Long
        End Structure
        Public Structure SpeedMeasure
            Sub New(ByVal BAS As Long)
                LoadSpeed(BAS)
            End Sub
            Public Sub LoadSpeed(ByVal BAS As Long)
                Me.BAS = BAS
                Me.KBAS = BAS / 1000
                Me.MBAS = BAS / 1000000
                If BAS > 1000000 Then
                    Me.SpeedString = Me.MBAS & " MB/s"
                ElseIf BAS > 1000 Then
                    Me.SpeedString = Me.KBAS & " KB/s"
                Else
                    Me.SpeedString = Me.BAS & " B/s"
                End If
            End Sub
            Public SpeedString As String
            Public BAS As Long
            Public KBAS As Long
            Public MBAS As Long
        End Structure
        Public Structure SizeMeasure
            Sub New(ByVal Bytes As Long)
                LoadSize(Bytes)
            End Sub
            Public Sub LoadSize(ByVal Bytes As Long)
                Me.Bytes = Bytes
                Me.KBytes = Bytes / 1000
                Me.MBytes = Bytes / 1000000
                Me.GBytes = Bytes / 1000000000
                If Bytes > 1000000000 Then
                    SizeString = Me.GBytes & " GB"
                ElseIf Bytes > 1000000 Then
                    SizeString = Me.MBytes & " MB"
                ElseIf Bytes > 1000 Then
                    SizeString = Me.KBytes & " KB"
                Else
                    SizeString = Me.Bytes & " bytes"
                End If
            End Sub
            Public SizeString As String
            Public Bytes As Long
            Public KBytes As Long
            Public MBytes As Long
            Public GBytes As Long
        End Structure
    
        Private t As Threading.Thread
        Public Sub StartDownload()
            If Me.Downloading = False Then Me.Paused = False
            If Me.Paused = False And Me.Downloading = False Then
                Try
                    t = New Threading.Thread(AddressOf DownLoadProcess)
                    t.IsBackground = True
                    t.Start()
                Catch ex As Exception
                    MsgBox(ex.Message & vbCrLf & vbCrLf & "Failed to start your download.", MsgBoxStyle.Critical)
                End Try
            Else
                Me.Paused = False
            End If
        End Sub
        Public Sub PauseDownload()
            Me.Paused = True
        End Sub
        Public Sub StopDownload()
            Me.stopdl = True
        End Sub
    
        Private Sub DownLoadProcess()
            Try
                Me.Downloading = True
                Me.dlfin = False
                Me.dledsize = 0
                If System.IO.File.Exists(Me.DestFileName) Then
                    SetAttr(Me.DestFileName, FileAttribute.Normal)
                    System.IO.File.Delete(Me.DestFileName)
                End If
                Dim ws As Net.WebResponse = Net.WebRequest.Create(Me.URL).GetResponse
                Me.tldlsize = ws.ContentLength
                If Me.tldlsize > 0 Then
                    Dim str As IO.Stream = ws.GetResponseStream()
                    Dim inBuf(10000000) As Byte
                    Dim bytesToRead As Integer = Me.tldlsize
                    Dim fstr As New IO.FileStream(Me.DestFileName, IO.FileMode.OpenOrCreate, IO.FileAccess.Write)
                    'Dim lastw As Long = 0
                    Dim t As New Stopwatch
                    Dim oldet As Long = 0
                    While bytesToRead > 0
                        If Me.stopdl = True Then Exit While
                        If Me.Paused = False Then
                            t.Start()
                            oldet = etime
                            Dim count As Long = 10000000
                            If bytesToRead < 10000000 Then count = bytesToRead
                            Dim n As Integer = str.Read(inBuf, 0, count)
                            If n = 0 Then Exit While
                            Me.dledsize += n
                            bytesToRead -= n
                            fstr.Write(inBuf, 0, n)
                            etime = t.ElapsedMilliseconds
                        Else
                            t.Stop()
                        End If
                    End While
                    t.Stop()
                    etime = t.ElapsedMilliseconds
                    fstr.Close()
                    ws.Close()
                    str.Close()
                Else
                    MsgBox("Failed to start your download because the link is invalid.", MsgBoxStyle.Critical)
                End If
            Catch ex As Exception
                MsgBox("Failed to start your download. " & vbCrLf & vbCrLf & ex.Message, MsgBoxStyle.Critical)
            End Try
            If Me.stopdl = True Then
                Try
                    System.IO.File.Delete(Me.DestFileName)
                Catch
                End Try
            End If
            Me.stopdl = False
            Me.Downloading = False
            Me.dlfin = True
        End Sub
    End Class
    It has all features you would possibly need: download speed, size and downloaded size, percentage, remaining and elapsed download time, pause download feature, and all with special enhancements for displaying speed, time and size.
    Last edited by bergerkiller; May 30th, 2010 at 05:06 AM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width