FTP download files larger than 2GB (VB.net) - vb.net

Missing last few bytes and file gets corrupted - bounty
I now added a bounty to solve this problem. I changed the integer types to int64 which seem to have solved part of the problem, but now when ever it finishes the download it sometimes misses the last 1-5 bytes, which in return corrupts the file, so it can't be unzipped. Is there another way of closing the stream so it ensures the files are fully downloaded, and avoid getting corrupted? I've since tried this simple code, but same problem happens.
Imports System.ComponentModel
Imports System.Net
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Control.CheckForIllegalCrossThreadCalls = False
End Sub
Dim WithEvents WC As New WebClient
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
WC.DownloadFileAsync(New Uri("ftp://dmr-ftp-user:dmrpassword#5.44.137.84/ESStatistikListeModtag/ESStatistikListeModtag-20160327-094743.zip"), "C:\XML\ESStatistikListeModtag-20160327-094743.zip.zip")
End Sub
Private Sub WC_DownloadProgressChanged(ByVal sender As Object, ByVal e As DownloadProgressChangedEventArgs) Handles WC.DownloadProgressChanged
ProgressBar1.Value = e.ProgressPercentage
If e.ProgressPercentage = 100 Then
MsgBox("File download - 100%") 'This message box does trigger once the download is complete, but file is still corrupted.
End If
End Sub
Private Sub WC_DownloadFileCompleted(sender As Object, e As AsyncCompletedEventArgs) Handles WC.DownloadFileCompleted
MsgBox("Complete") ' This message box doesn't trigger!
End Sub
End Class
OLD QUESTION:
I'm trying to download a zip file from an FTP server with my vb.net application. My current source code is posted below. This works fine for smaller files, but when I exceed a limit of 2GB I get the following exception:
"Arithmetic operation resulted in an overflow"
It's a file with the size of about 2.5 GB and increasing slightly each weak (about 20 MB), so I need a solution which can handle large files, hopefully with no limit. Eventually I would like to unzip the file with the program too, so if you have any ideas for doing this, you can post this as well. Thanks!
Private Sub Download(ByVal filePath As String, ByVal fileName As String)
FTPSettings.IP = "0.0.0.0"
FTPSettings.UserID = "ftp-user"
FTPSettings.Password = "ftp-pass"
Dim reqFTP As FtpWebRequest = Nothing
Dim ftpStream As Stream = Nothing
Try
Dim outputStream As New FileStream(filePath + "\" + fileName, FileMode.Create)
reqFTP = DirectCast(FtpWebRequest.Create(New Uri("ftp://" + FTPSettings.IP + "/" + fileName)), FtpWebRequest)
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile
reqFTP.UseBinary = True
reqFTP.Credentials = New NetworkCredential(FTPSettings.UserID, FTPSettings.Password)
Dim response As FtpWebResponse = DirectCast(reqFTP.GetResponse(), FtpWebResponse)
ftpStream = response.GetResponseStream()
Dim cl As Long = response.ContentLength
Dim bufferSize As Integer = 2048
Dim readCount As Int64
Dim buffer As Byte() = New Byte(bufferSize - 1) {}
Dim size As Int64
readCount = ftpStream.Read(buffer, 0, bufferSize)
While readCount > 0
outputStream.Write(buffer, 0, readCount)
readCount = ftpStream.Read(buffer, 0, bufferSize)
If readCount = bufferSize Then
size += readCount
Label1.Text = size
Label1.Refresh()
End If
End While
ftpStream.Close()
outputStream.Close()
response.Close()
Catch ex As Exception
MsgBox(ex.Message)
If ftpStream IsNot Nothing Then
ftpStream.Close()
ftpStream.Dispose()
End If
Throw New Exception(ex.Message.ToString())
End Try
End Sub
Public NotInheritable Class FTPSettings
Private Sub New()
End Sub
Public Shared Property IP() As String
Get
Return m_IP
End Get
Set(ByVal value As String)
m_IP = value
End Set
End Property
Private Shared m_IP As String
Public Shared Property UserID() As String
Get
Return m_UserID
End Get
Set(ByVal value As String)
m_UserID = value
End Set
End Property
Private Shared m_UserID As String
Public Shared Property Password() As String
Get
Return m_Password
End Get
Set(ByVal value As String)
m_Password = value
End Set
End Property
Private Shared m_Password As String
End Class
End Class

I've had similar problems with WebClient before, specially if using it with the WithEvents statement.
See if re-writing your code like this solves the problem:
Imports System.ComponentModel
Imports System.Net
Public Class Form1
Private wc As New WebClient()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
wc = New WebClient()
AddHandler wc.DownloadProgressChanged, Sub(s As Object, ByVal e As DownloadProgressChangedEventArgs)
Me.Invoke(New MethodInvoker(Sub() ProgressBar1.Value = e.ProgressPercentage))
End Sub
AddHandler wc.DownloadFileCompleted, Sub(s As Object, e As ComponentModel.AsyncCompletedEventArgs)
MsgBox("Complete")
End Sub
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
wc.DownloadFileAsync(New Uri("ftp://dmr-ftp-user:dmrpassword#5.44.137.84/ESStatistikListeModtag/ESStatistikListeModtag-20160327-094743.zip"), "C:\XML\ESStatistikListeModtag-20160327-094743.zip.zip")
End Sub
End Class

Related

How to download multiple files in list box using vb.net

I want to download multiples files and the download links in list box, Is there any way to do that using WebClient, i saw people do that by download file by file by it look difficult way and i want to show current downloading speed ,current file size and progress of total process
I solved this proplem by that way:
Imports System.Net
Public Class Form1
Private WithEvents DonloadFile As WebClient
Dim stopwatch As Stopwatch = New Stopwatch
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ListBox1.SelectedIndex = 0
End Sub
Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
stopwatch.Start()
DonloadFile = New WebClient
Try
DonloadFile.DownloadFileAsync(New Uri(ListBox1.SelectedItem.ToString), "C:\Users\" & Environment.UserName & "\Desktop\" & IO.Path.GetFileName(ListBox1.SelectedItem.ToString))
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Private Sub DonloadFile_DownloadProgressChanged(sender As Object, e As DownloadProgressChangedEventArgs) Handles DonloadFile.DownloadProgressChanged
Dim y As Integer = (e.BytesReceived / 1024) / 1024
Label6.Text = "Download Speed: " & String.Format("{0} MB/s", (y / (stopwatch.Elapsed.TotalSeconds)).ToString("0.00"))
Label2.Text = "Current File Size: " & Math.Round(e.TotalBytesToReceive / (1024 * 1024), 1) & " MB"
Label3.Text = "Current File Persent: " & e.ProgressPercentage
Label1.Text = "Total Files: " & ListBox1.Items.Count.ToString()
If ListBox1.Items.Count.ToString > (ListBox1.SelectedIndex + 1) Then
If e.ProgressPercentage = 100 Then
ListBox1.SelectedIndex += 1
End If
Else
MessageBox.Show("Download completed successful", "Info")
End If
End Sub
Private Sub DonloadFile_DownloadDataCompleted(sender As Object, e As DownloadDataCompletedEventArgs) Handles DonloadFile.DownloadDataCompleted
stopwatch.Reset()
End Sub
End Class
thanks for #Fawlty
Here is some code I wrote to demonstrate how you could do this. I created a FileDownloader class as this will allow you to get the source url and destination filename when the download completes. I have also added an event for progress. The problem with just using the WebClient class on its own is that you lose track of which file is being processed in the events.
Imports System.ComponentModel
Imports System.Net
' A class for downloading files, with progress and finished events
Public Class FileDownloader
' Private storage
Private FileURL As String = ""
Private SaveToPath As String = ""
' A class to return our result in
Public Class FileDownloaderFileDownloadedEventArgs
Public Property DownloadedURL As String
Public Property SaveToPath As String
Public Sub New(DownloadedURL As String, SaveToPath As String)
Me.DownloadedURL = DownloadedURL
Me.SaveToPath = SaveToPath
End Sub
End Class
' A class to show progress
Public Class FileDownloaderProgressEventArgs
Public Property DownloadURL As String
Public Property SaveToPath As String
Public Property TotalBytes As Long
Public Property ProgressBytes As Long
Public Property ProgressPercent As Integer
Public Property UserState As Object
Public Sub New(DownloadURL As String, SaveToPath As String, TotalBytes As Long, ProgressBytes As Long, ProgressPercent As Integer, UserState As Object)
Me.DownloadURL = DownloadURL
Me.SaveToPath = SaveToPath
Me.TotalBytes = TotalBytes
Me.ProgressBytes = ProgressBytes
Me.ProgressPercent = ProgressPercent
Me.UserState = UserState
End Sub
End Class
' The event to raise when the file is downloaded
Public Event FileDownloaded(sender As Object, e As FileDownloaderFileDownloadedEventArgs)
' The event to raise when there is progress
Public Event Progress(sender As Object, e As FileDownloaderProgressEventArgs)
' Pass in the URL and FilePath when creating the downloader object
Public Sub New(FileURL As String, SaveToPath As String)
Me.FileURL = FileURL
Me.SaveToPath = SaveToPath
End Sub
' Call Download() to do the work
Public Sub Download()
Using wc As New WebClient
AddHandler wc.DownloadFileCompleted, AddressOf DownloadFileCompleted
AddHandler wc.DownloadProgressChanged, AddressOf DownloadProgressChanged
wc.DownloadFileAsync(New Uri(FileURL), SaveToPath)
End Using
End Sub
' Catch the download complete and raise our event
Private Sub DownloadProgressChanged(ByVal sender As Object, ByVal e As DownloadProgressChangedEventArgs)
RaiseEvent Progress(Me, New FileDownloaderProgressEventArgs(FileURL, SaveToPath, e.TotalBytesToReceive, e.BytesReceived, e.ProgressPercentage, e.UserState))
End Sub
Private Sub DownloadFileCompleted(sender As Object, e As AsyncCompletedEventArgs)
' Some code you want to run after each file has downloaded
RaiseEvent FileDownloaded(Me, New FileDownloaderFileDownloadedEventArgs(FileURL, SaveToPath))
End Sub
End Class
#Region "How to use the FileDownloader class"
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
' Loop the URLs in the ListBox
For Each item In ListBox1.Items
' Create a FileDownloader object to handler each one
Dim FD = New FileDownloader(item, "c:\temp\" & IO.Path.GetFileName(item))
' Attach the event handlers
AddHandler FD.FileDownloaded, AddressOf FileDownloaded
AddHandler FD.Progress, AddressOf Progress
' Start the download
FD.Download()
Next
End Sub
' Event handler for file download completed
Private Sub FileDownloaded(sender As Object, e As FileDownloader.FileDownloaderFileDownloadedEventArgs)
tb_Log.AppendText(e.DownloadedURL & " Downloaded To: " & e.SaveToPath & vbCrLf)
End Sub
' Event handler for progress
Private Sub Progress(sender As Object, e As FileDownloader.FileDownloaderProgressEventArgs)
tb_Log.AppendText(IO.Path.GetFileName(e.DownloadURL) & " " & e.ProgressPercent & "% downloaded" & vbCrLf)
End Sub
#End Region

How to download multiple URLs at the same time?

Public Class Form1
For i As Integer = 0 To RichTextBox1.Lines.Length - 1
wreq=System.Net.WebRequest.Create("i th Internet address")
wreq.AutomaticDecompression = Net.DecompressionMethods.GZip
wres = wreq.GetResponse
Dim s As System.IO.Stream = wres.GetResponseStream
Dim sr As New System.IO.StreamReader(s)
html = sr.ReadToEnd
s = html.Split(";")
'here is other codes
Next
End Class
this is part of my program.
When I use this, it takes a long time for everyone to download. How can I download all the addresses at the same time?
I found the following code on the internet enter code here to do this, but I do not know how to use it in the my program. Please help. Thank you.
Imports System.Threading.Tasks
Imports System.Net
Imports System.IO
Public Class Form1
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
'Start a background task so as not to freeze up the UI.
Me.BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim files As String() 'Get file paths.
'Download multiple files simultaneously.
Parallel.ForEach(files,
Sub(f) Call New WebClient().DownloadFile(f,
Path.Combine("local folder here",
Path.GetFileName(f))))
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
MessageBox.Show("All files downloaded")
End Sub
End Class
Take a look on this. Might be a good start (part of your code implemented on each method).
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim urls() As String = RichTextBox1.Lines.Select(Function(url) Trim(url))
Parallel.ForEach(urls, Sub(f)
If Not String.IsNullOrEmpty(f) Then
DownloadAsync(f)
End If
End Sub)
End Sub
Function DownloadAsync(URL As String) As Task(Of Boolean)
Try
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
Dim html As String = ""
Dim result As Boolean
Dim request As HttpWebRequest = HttpWebRequest.Create(URL)
request.AutomaticDecompression = DecompressionMethods.GZip
request.Timeout = 500
request.Method = "GET"
request.UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0"
Using response As Task(Of WebResponse) = request.GetResponseAsync
If response.Result IsNot Nothing Then
Using ioStream As IO.Stream = response.Result.GetResponseStream
Using sr As New System.IO.StreamReader(ioStream)
html = sr.ReadToEnd
Dim s() As String = html.Split(";"c)
For Each sl In s
Debug.WriteLine(sl)
Next
End Using
result = True
End Using
End If
End Using
Return Task.FromResult(result)
Catch ex As Exception
Debug.WriteLine(ex.Message)
End Try
Return Task.FromResult(False)
End Function

Trying to change a timer once a button is pressed

I have a check going every 60 seconds, if the alarm is true it will open form2 play a song etc.
but the button on form2 should set the waittimer = 180000 which should make the next check occur half an half an hour later.
I'm not used to using timers, what am I doing wrong?
Public Class Form1
Public Property waittimer As Integer
Public Property playsong As Boolean = True
Private WithEvents Tmr As New Timer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If (Process.GetProcessesByName(Process.GetCurrentProcess.ProcessName).Length > 1) Then
Application.Exit()
End If
Tmr.Enabled = False
Tmr.Interval = TimeSpan.FromSeconds(60).TotalMilliseconds
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub NotifyIcon1_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles NotifyIcon1.MouseDoubleClick
playsong = False
Try
' Create a request for the URL.
Dim request As WebRequest = _
WebRequest.Create("http://example.com/example.aspx")
' If required by the server, set the credentials.
request.Credentials = CredentialCache.DefaultCredentials
' Get the response.
Dim response As WebResponse = request.GetResponse()
' Display the status.
Console.WriteLine(CType(response, HttpWebResponse).StatusDescription)
' Get the stream containing content returned by the server.
Dim dataStream As Stream = response.GetResponseStream()
' Open the stream using a StreamReader for easy access.
Dim reader As New StreamReader(dataStream)
' Read the content.
Dim responseFromServer As String = reader.ReadToEnd()
' Display the content.
Console.WriteLine(responseFromServer)
' Clean up the streams and the response.
reader.Close()
response.Close()
Dim responseArray() As String
responseArray = Split(responseFromServer, "|")
Dim D As New Data
D.maxcalls = responseArray(0)
D.cph = responseArray(1)
D.mht = responseArray(2)
D.alarm = responseArray(3)
Form2.startsong(D)
Catch ex As Exception
End Try
playsong = True
End Sub
Private Sub ExitToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ExitToolStripMenuItem.Click
Application.Exit()
End
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Try
If waittimer = 180000 Then
Tmr.Interval = waittimer
Tmr.Start()
waittimer = 60000
Else
waittimer = 60000
End If
' Create a request for the URL.
Dim request As WebRequest = _
WebRequest.Create("http://example.com/example.aspx")
' If required by the server, set the credentials.
request.Credentials = CredentialCache.DefaultCredentials
' Get the response.
Dim response As WebResponse = request.GetResponse()
' Display the status.
Console.WriteLine(CType(response, HttpWebResponse).StatusDescription)
' Get the stream containing content returned by the server.
Dim dataStream As Stream = response.GetResponseStream()
' Open the stream using a StreamReader for easy access.
Dim reader As New StreamReader(dataStream)
' Read the content.
Dim responseFromServer As String = reader.ReadToEnd()
' Display the content.
Console.WriteLine(responseFromServer)
' Clean up the streams and the response.
reader.Close()
response.Close()
Dim responseArray() As String
responseArray = Split(responseFromServer, "|")
Dim D As New Data
D.maxcalls = responseArray(0)
D.cph = responseArray(1)
D.mht = responseArray(2)
D.alarm = responseArray(3)
D.forcealarm = False
e.Result = D
Catch ex As Exception
Dim D As New Data
D.maxcalls = 404
D.cph = 404
D.mht = 404
D.alarm = True
D.forcealarm = True
e.Result = D
End Try
Tmr.Interval = waittimer
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If Not IsNothing(e.Result) Then
Dim strtime As String
Dim englandtime = System.TimeZoneInfo.ConvertTime(Now, TimeZoneInfo.FindSystemTimeZoneById("UTC"))
strtime = DatePart(Microsoft.VisualBasic.DateInterval.Hour, englandtime) & DatePart(Microsoft.VisualBasic.DateInterval.Minute, englandtime)
Dim D As Data = DirectCast(e.Result, Data)
If D.forcealarm = True Then
Form2.startsong(D)
End If
If D.alarm Then
If strtime < 730 And strtime > 0 Then
Else
Form2.startsong(D)
End If
End If
End If
Tmr.Start()
End Sub
Private Sub Tmr_Tick(sender As Object, e As System.EventArgs) Handles Tmr.Tick
Tmr.Stop()
BackgroundWorker1.RunWorkerAsync()
End Sub
End Class
Public Class Data
Public Property maxcalls As Integer
Public Property cph As Integer
Public Property mht As Integer
Public Property alarm As Boolean
Public Property forcealarm As Boolean
End Class
Form2
Public Class Form2
Public audio As New AudioFile(My.Application.Info.DirectoryPath & "\Help.mp3")
Public Sub startsong(ByVal D As Data)
Me.Show()
MHTvalue.Text = D.mht.ToString
Maxcallsvalue.Text = D.maxcalls
CPHvalue.Text = D.cph
If Form1.playsong = True Then
audio.Play()
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' Me.Close()
audio.Stop()
Form1.waittimer = 180000
End Sub
Private Sub Form2_Closing(sender As Object, e As EventArgs) Handles MyBase.Load
audio.Stop()
Form1.waittimer = 180000
End Sub
Private Sub Form2_Minimize(sender As Object, e As EventArgs) Handles MyBase.Load
audio.Stop()
Form1.waittimer = 180000
End Sub
Thats probably because your timer on the original form1 instance never get re configured by your code. You are instead setting a timer on a new copy of form 1 that is not running (showing).
You need to get the running instance of form1 that you originally opened. A technique I use for something like this, is to tag my form I will be looking for, and then stepping through the form instances currently running, getting my form via its tag, setting that found form equal to the object I am working with, and THEN use the properties/methods of that form.
Set your form1's tag to "myTag".
Then on form 2:
For Each f As Form In My.Application.OpenForms
If Not f.InvokeRequired Then
'Can access the form directly.
If f.Tag = "myTag" Then
'this is my form
Dim fcast As New form1
fcast = f
fcast.<---- use your methods / properties...
End If
End If
Next
Just change:
Public Property waittimer As Integer
To:
Public Property waittimer As Integer
Get
Return Tmr.Interval
End Get
Set(value As Integer)
If value > 0 Then
Tmr.Interval = value
End If
End Set
End Property
You were changing the waittimer value, but not the actual Interval() of the Timer as well. This links the two together.

Measuring download speed

I'm downloading a file using the following:
Dim client As WebClient = New WebClient()
client.DownloadFileAsync(New Uri("http://cachefly.cachefly.net/100mb.test"), "C:\Users\Dir\100mb.test")
The file downloads and saves into the C://Users/Dir/100mb.test, but while its downloading I would like to display the download speed in a label. How can I do this? I have read many tutorials, but most of them doesn't works or are outdated. I'm a newbie with vb.net, so I can't really write something on my own, could you give me any solutions?
May I suggest something different?
Imports System.Net
Public Class Form1
Private tmp = IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp, "snafu.fubar")
Private Downloading As Boolean = False
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If Downloading Then Exit Sub
Downloading = True
Dim wc As New WebClient
AddHandler wc.DownloadProgressChanged, AddressOf wc_ProgressChanged
AddHandler wc.DownloadFileCompleted, AddressOf wc_DownloadDone
wc.DownloadFileAsync(New Uri("http://cachefly.cachefly.net/100mb.test"), tmp, Stopwatch.StartNew)
End Sub
Private Sub wc_DownloadDone(sender As Object, e As System.ComponentModel.AsyncCompletedEventArgs)
Downloading = False
End Sub
Private Sub wc_ProgressChanged(sender As Object, e As DownloadProgressChangedEventArgs)
Me.Label1.Text = (e.BytesReceived / (DirectCast(e.UserState, Stopwatch).ElapsedMilliseconds / 1000.0#)).ToString("#")
End Sub
End Class
Because it makes no sense to determine the speed by the last chunk of bytes received, but instead you measure the total number of bytes and divide by the TOTAL time. Passing a stopwatch instance to the eventhandler has the advantage that it doesnt 'spoil' your class code - it''s visible only where it's needed.
This will give you percentage in the mean time. You could probably calculate from the percentage given a start time using DateTime.Now the speed in which it the download is taking:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Try
Dim client As WebClient = New WebClient()
AddHandler client.DownloadProgressChanged, AddressOf ProgChanged
client.DownloadFileAsync(New Uri("http://cachefly.cachefly.net/100mb.test"), "C:\Users\Dir\100mb.test")
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Private Sub ProgChanged(ByVal sender As Object, ByVal e As DownloadProgressChangedEventArgs)
Dim progressPercentage As Integer = e.ProgressPercentage
End Sub
Define globals:
Dim lastUpdate As DateTime
Dim lastBytes As Long = 0
You'll need to assign an Event for progress:
Dim client As WebClient = New WebClient()
client.DownloadFileAsync(New Uri("http://cachefly.cachefly.net/100mb.test"), "C:\Users\Dir\100mb.test")
client.DownloadProgressChanged += Function(sender, e) progressChanged(e.BytesReceived)
The Event:
Private Sub progressChanged(bytes As Long)
If lastBytes = 0 Then
lastUpdate = DateTime.Now
lastBytes = bytes
Return
End If
Dim now = DateTime.Now
Dim timeSpan = now - lastUpdate
If Not timeSpan.Seconds = 0
Dim bytesChange = bytes - lastBytes
Dim bytesPerSecond = bytesChange / timeSpan.Seconds
lastBytes = bytes
lastUpdate = now
End If
End Sub
And you have the calculations of bytes per second.
label.Text = bytesPerSecond.ToString() + "B/s";
Try this:
Try this only when you're downloading through a backgroundworker
Private Sub worker_DoWork(Byval sender As Object, Byval e As DoWorkEventArgs)
Dim req As WebRequest = WebRequest.Create(downloadUrl) 'Make a request for the url of the file to be downloaded
Dim resp As WebResponse = req.GetResponse 'Ask for the response
Dim fs As New FileStream(path to download to, FileMode.CreateNew) 'Create a new FileStream that writes to the desired download path
Dim buffer(8192) As Byte 'Make a buffer
Dim downloadedsize As Long = 0
Dim downloadedTime As Long = 0
Dim dlSpeed As Long = 0
Dim currentSize As Long = 0 'Size that has been downloaded
Dim totalSize As Long = req.ContentLength 'Total size of the file that has to be downloaded
Do While currentSize < totalSize
Dim read As Integer = resp.GetResponseStream.Read(buffer, 0, 8192) 'Read the buffer from the response the WebRequest gave you
fs.Write(buffer, 0, read) 'Write to filestream that you declared at the beginning of the DoWork sub
currentSize += read
downloadedSize += read
downloadedTime += 1 'Add 1 millisecond for every cycle the While field makes
If downloadedTime = 1000 Then 'Then, if downloadedTime reaches 1000 then it will call this part
dlSpeed = (downloadedSize / TimeSpan.FromMilliseconds(downloadedTime).TotalSeconds) 'Calculate the download speed by dividing the downloadedSize by the total formatted seconds of the downloadedTime
downloadedTime = 0 'Reset downloadedTime and downloadedSize
downloadedSize = 0
End If
End While
fs.Close() 'Close the FileStream first, or the FileStream will crash.
resp.Close() 'Close the response
End Sub
Sorry for not using proper formatting, but this is a solution in itself.

Drawing a WebBrowser control to a bitmap

I'm trying to save a panel control as a bitmap using the following code (VB.net):
Private Sub SaveFileDialog1_FileOk(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles SaveFileDialog1.FileOk
filename = SaveFileDialog1.FileName
Dim CardImg As New Bitmap(Panel1.Width, Panel1.Height)
Panel1.DrawToBitmap(CardImg, Panel1.ClientRectangle)
CardImg.Save(filename, System.Drawing.Imaging.ImageFormat.Bmp)
End Sub
Everything works, except the Web browser control, which is docked in the panel. In the saved bitmap, this control appears as only white space, while everything else in the panel renders out fine. Any ideas?
When I saved snapshots from a WebBrowser I called .Focus() on it after navigating -- and somehow the white picture results magically disapperard. Don't know why, but it worked for me.
Download "ScreenCapture.vb" from http://www.vbforums.com/showthread.php?t=385497,
use CaptureDeskTopRectangle but you should not use the location of your panel because it's
referenced to panel parent you should use yourpanel.PointToScreen() to identify the correct
rectangle.
Regards..
UPDATE:
Check this out, you gon like it, i similute your case and it's working:
Private Sub btnBrowse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBrowse.Click
Try
Using fl As New SaveFileDialog
fl.Filter = "PNG images|*.png"
If fl.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim sc As New screencapture
Dim pt = WebBrowser1.Parent.PointToScreen(WebBrowser1.Location)
Dim rec As New Rectangle(pt.X, pt.Y, WebBrowser1.Width, WebBrowser1.Height)
Application.DoEvents()
Threading.Thread.Sleep(500)
Using bmp As Bitmap = sc.CaptureDeskTopRectangle(rec, WebBrowser1.Width, WebBrowser1.Height)
bmp.Save(fl.FileName, System.Drawing.Imaging.ImageFormat.Png)
End Using
End If
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Update 2:
In Form:
Private Sub btnBrowse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBrowse.Click
Try
Using fl As New SaveFileDialog
fl.Filter = "PNG images|*.png"
If fl.ShowDialog = Windows.Forms.DialogResult.OK Then
JSsetTimeout.SetTimeout(Me, "TakeShot", 1500, fl.FileName)
End If
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Sub TakeShot(ByVal FilePath As String)
Try
Application.DoEvents()
Dim sc As New screencapture
Dim pt = WebBrowser1.Parent.PointToScreen(WebBrowser1.Location)
Dim rec As New Rectangle(pt.X, pt.Y, WebBrowser1.Width, WebBrowser1.Height)
Using bmp As Bitmap = sc.CaptureDeskTopRectangle(rec, WebBrowser1.Width, WebBrowser1.Height)
bmp.Save(FilePath, System.Drawing.Imaging.ImageFormat.Png)
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
To Create a time delay add the class below :
Public Class JSsetTimeout
Public res As Object = Nothing
Dim WithEvents tm As Timer = Nothing
Dim _MethodName As String
Dim _args() As Object
Dim _ClassInstacne As Object = Nothing
Public Shared Sub SetTimeout(ByVal ClassInstacne As Object, ByVal obj As String, ByVal TimeSpan As Integer, ByVal ParamArray args() As Object)
Dim jssto As New JSsetTimeout(ClassInstacne, obj, TimeSpan, args)
End Sub
Public Sub New(ByVal ClassInstacne As Object, ByVal obj As String, ByVal TimeSpan As Integer, ByVal ParamArray args() As Object)
If obj IsNot Nothing Then
_MethodName = obj
_args = args
_ClassInstacne = ClassInstacne
tm = New Timer With {.Interval = TimeSpan, .Enabled = False}
AddHandler tm.Tick, AddressOf tm_Tick
tm.Start()
End If
End Sub
Private Sub tm_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles tm.Tick
tm.Stop()
RemoveHandler tm.Tick, AddressOf tm_Tick
If Not String.IsNullOrEmpty(_MethodName) AndAlso _ClassInstacne IsNot Nothing Then
res = CallByName(_ClassInstacne, _MethodName, CallType.Method, _args)
Else
res = Nothing
End If
End Sub
End Class