BadBigShot
asked on
How to translate a C# program (with delegate variables, event and asyncroneous callback functions) to VB.NET?
Hi! I've been spending a lot of time on trying to translate a C# code to VB.NET. This code is for downloading files through HTTP asyncroneously. You can find the original C# source code at http://www.codeproject.com/csharp/WebDownload.asp
And here's my VB.NET code which obviously isn't working:
'''''''''''''''''''''''''' '''''''''' '''''''''' ''
DOWNLOADTHREAD.VB
'''''''''''''''''''''''''' '''''''''' '''''''''' ''
Imports System
Namespace RJH.Utils.WebDownload
Public Delegate Sub DownloadCompleteHandler(By Val dataDownloaded() As Byte)
Public Class DownloadThread
Public Event CompleteCallback As DownloadCompleteHandler
Public Event ProgressCallback As DownloadProgressHandler
Public _downloadUrl As String = ""
Public Property DownloadUrl() As String
Get
Return _downloadUrl
End Get
Set(ByVal Value As String)
_downloadUrl = Value
End Set
End Property
Public Function Download()
If Not (CompleteCallback Is Nothing) And DownloadUrl <> "" Then
Dim webDL As WebDownload = New WebDownload
Dim downloadedData() As Byte = webDL.Download(DownloadUrl , ProgressCallback)
RaiseEvent CompleteCallback(downloade dData)
End If
End Function
End Class
End Namespace
'''''''''''''''''''''''''' '''''''''' '''''''''' ''
WEBDOWNLOAD.VB
'''''''''''''''''''''''''' '''''''''' '''''''''' ''
Imports System
Imports System.Net
Imports System.IO
Imports System.Threading
Namespace RJH.Utils.WebDownload
Public Delegate Sub DownloadProgressHandler(By Val bytesRead As Integer, ByVal totalBytes As Integer)
'The RequestState class passes data across async calls.
Public Class DownloadInfo
Const BufferSize As Integer = 1024
Public BufferRead() As Byte
Public useFastBuffers As Boolean
Public dataBufferFast() As Byte
Public dataBufferSlow As System.Collections.ArrayLi st
Public dataLength As Integer
Public bytesProcessed As Integer
Public Request As WebRequest
Public ResponseStream As Stream
Public ProgressCallback As DownloadProgressHandler
Public Sub New()
BufferRead = New Byte(BufferSize) {}
Request = Nothing
dataLength = -1
bytesProcessed = 0
useFastBuffers = True
End Sub
End Class
Public Class WebDownload
Public allDone As ManualResetEvent = New ManualResetEvent(False)
Const BUFFER_SIZE As Integer = 1024
Public Function Download(ByVal url As String, ByVal progressCB As DownloadProgressHandler) As Byte()
'Ensure flag set correctly.
allDone.Reset()
'Get the URI from the command line.
Dim httpSite As Uri = New Uri(url)
'Create the request object.
Dim req As WebRequest = WebRequest.Create(httpSite )
'Create the state object.
Dim info As DownloadInfo = New DownloadInfo
'Put the request into the state object so it can be passed around.
info.Request = req
'''''''''''''''''''''
'Assign the callbacks
info.ProgressCallback = progressCB
'Issue the async request.
Dim r As IAsyncResult = req.BeginGetResponse(New AsyncCallback(AddressOf ResponseCallback), info)
'Wait until the ManualResetEvent is set so that the application
'does not exit until after the callback is called.
allDone.WaitOne()
'Pass back the downloaded information.
If info.useFastBuffers Then
Return info.dataBufferFast
Else
Dim data() As Byte = New Byte(info.dataBufferSlow.C ount) {}
Dim b As Integer = 0
For b = 0 To info.dataBufferSlow.Count - 1
data(b) = info.dataBufferSlow(b)
Next
Return data
End If
End Function
Private Sub ResponseCallback(ByVal ar As IAsyncResult)
'Get the DownloadInfo object from the async result were
'we're storing all of the temporary data and the download
'buffer.
Dim info As DownloadInfo = ar.AsyncState
'Get the WebRequest from RequestState.
Dim req As WebRequest = info.Request
'Call EndGetResponse, which produces the WebResponse object
'that came from the request issued above.
Dim resp As WebResponse = req.EndGetResponse(ar)
'Find the data size from the headers.
Dim strContentLength As String = resp.Headers("Content-Leng th")
If strContentLength <> 0 Then
info.dataLength = Convert.ToInt32(strContent Length)
info.dataBufferFast = New Byte(info.dataLength) {}
Else
info.useFastBuffers = False
info.dataBufferSlow = New System.Collections.ArrayLi st(BUFFER_ SIZE)
End If
'Start reading data from the response stream.
Dim ResponseStream As Stream = resp.GetResponseStream()
'Store the response stream in RequestState to read
'the stream asynchronously.
info.ResponseStream = ResponseStream
'Pass do.BufferRead to BeginRead.
Dim iarRead As IAsyncResult = ResponseStream.BeginRead(i nfo.Buffer Read, 0, BUFFER_SIZE, New AsyncCallback(AddressOf ReadCallBack), info)
End Sub
Private Sub ReadCallBack(ByVal asyncResult As IAsyncResult)
Dim b As Integer
'Get the DownloadInfo object from AsyncResult.
Dim info As DownloadInfo = asyncResult.AsyncState
'Retrieve the ResponseStream that was set in RespCallback.
Dim responseStream As Stream = info.ResponseStream
'Read info.BufferRead to verify that it contains data.
Dim bytesRead As Integer = responseStream.EndRead(asy ncResult)
If bytesRead > 0 Then
If info.useFastBuffers Then
System.Array.Copy(info.Buf ferRead, 0, info.dataBufferFast, info.bytesProcessed, bytesRead)
Else
For b = 0 To bytesRead - 1
info.dataBufferSlow.Add(in fo.BufferR ead(b))
Next
End If
info.bytesProcessed += bytesRead
'If a registered progress-callback, inform it of our
'download progress so far.
If Not (info.ProgressCallback Is Nothing) Then
info.ProgressCallback(info .bytesProc essed, info.dataLength)
End If
'Continue reading data until responseStream.EndRead returns –1.
Dim ar As IAsyncResult = responseStream.BeginRead( _
info.BufferRead, 0, BUFFER_SIZE, New AsyncCallback(AddressOf ReadCallBack), info)
Else
responseStream.Close()
allDone.Set()
End If
End Sub
End Class
End Namespace
'''''''''''''''''''''''''' '''''''''' '
Could someone help me debug this thing?
And here's my VB.NET code which obviously isn't working:
''''''''''''''''''''''''''
DOWNLOADTHREAD.VB
''''''''''''''''''''''''''
Imports System
Namespace RJH.Utils.WebDownload
Public Delegate Sub DownloadCompleteHandler(By
Public Class DownloadThread
Public Event CompleteCallback As DownloadCompleteHandler
Public Event ProgressCallback As DownloadProgressHandler
Public _downloadUrl As String = ""
Public Property DownloadUrl() As String
Get
Return _downloadUrl
End Get
Set(ByVal Value As String)
_downloadUrl = Value
End Set
End Property
Public Function Download()
If Not (CompleteCallback Is Nothing) And DownloadUrl <> "" Then
Dim webDL As WebDownload = New WebDownload
Dim downloadedData() As Byte = webDL.Download(DownloadUrl
RaiseEvent CompleteCallback(downloade
End If
End Function
End Class
End Namespace
''''''''''''''''''''''''''
WEBDOWNLOAD.VB
''''''''''''''''''''''''''
Imports System
Imports System.Net
Imports System.IO
Imports System.Threading
Namespace RJH.Utils.WebDownload
Public Delegate Sub DownloadProgressHandler(By
'The RequestState class passes data across async calls.
Public Class DownloadInfo
Const BufferSize As Integer = 1024
Public BufferRead() As Byte
Public useFastBuffers As Boolean
Public dataBufferFast() As Byte
Public dataBufferSlow As System.Collections.ArrayLi
Public dataLength As Integer
Public bytesProcessed As Integer
Public Request As WebRequest
Public ResponseStream As Stream
Public ProgressCallback As DownloadProgressHandler
Public Sub New()
BufferRead = New Byte(BufferSize) {}
Request = Nothing
dataLength = -1
bytesProcessed = 0
useFastBuffers = True
End Sub
End Class
Public Class WebDownload
Public allDone As ManualResetEvent = New ManualResetEvent(False)
Const BUFFER_SIZE As Integer = 1024
Public Function Download(ByVal url As String, ByVal progressCB As DownloadProgressHandler) As Byte()
'Ensure flag set correctly.
allDone.Reset()
'Get the URI from the command line.
Dim httpSite As Uri = New Uri(url)
'Create the request object.
Dim req As WebRequest = WebRequest.Create(httpSite
'Create the state object.
Dim info As DownloadInfo = New DownloadInfo
'Put the request into the state object so it can be passed around.
info.Request = req
'''''''''''''''''''''
'Assign the callbacks
info.ProgressCallback = progressCB
'Issue the async request.
Dim r As IAsyncResult = req.BeginGetResponse(New AsyncCallback(AddressOf ResponseCallback), info)
'Wait until the ManualResetEvent is set so that the application
'does not exit until after the callback is called.
allDone.WaitOne()
'Pass back the downloaded information.
If info.useFastBuffers Then
Return info.dataBufferFast
Else
Dim data() As Byte = New Byte(info.dataBufferSlow.C
Dim b As Integer = 0
For b = 0 To info.dataBufferSlow.Count - 1
data(b) = info.dataBufferSlow(b)
Next
Return data
End If
End Function
Private Sub ResponseCallback(ByVal ar As IAsyncResult)
'Get the DownloadInfo object from the async result were
'we're storing all of the temporary data and the download
'buffer.
Dim info As DownloadInfo = ar.AsyncState
'Get the WebRequest from RequestState.
Dim req As WebRequest = info.Request
'Call EndGetResponse, which produces the WebResponse object
'that came from the request issued above.
Dim resp As WebResponse = req.EndGetResponse(ar)
'Find the data size from the headers.
Dim strContentLength As String = resp.Headers("Content-Leng
If strContentLength <> 0 Then
info.dataLength = Convert.ToInt32(strContent
info.dataBufferFast = New Byte(info.dataLength) {}
Else
info.useFastBuffers = False
info.dataBufferSlow = New System.Collections.ArrayLi
End If
'Start reading data from the response stream.
Dim ResponseStream As Stream = resp.GetResponseStream()
'Store the response stream in RequestState to read
'the stream asynchronously.
info.ResponseStream = ResponseStream
'Pass do.BufferRead to BeginRead.
Dim iarRead As IAsyncResult = ResponseStream.BeginRead(i
End Sub
Private Sub ReadCallBack(ByVal asyncResult As IAsyncResult)
Dim b As Integer
'Get the DownloadInfo object from AsyncResult.
Dim info As DownloadInfo = asyncResult.AsyncState
'Retrieve the ResponseStream that was set in RespCallback.
Dim responseStream As Stream = info.ResponseStream
'Read info.BufferRead to verify that it contains data.
Dim bytesRead As Integer = responseStream.EndRead(asy
If bytesRead > 0 Then
If info.useFastBuffers Then
System.Array.Copy(info.Buf
Else
For b = 0 To bytesRead - 1
info.dataBufferSlow.Add(in
Next
End If
info.bytesProcessed += bytesRead
'If a registered progress-callback, inform it of our
'download progress so far.
If Not (info.ProgressCallback Is Nothing) Then
info.ProgressCallback(info
End If
'Continue reading data until responseStream.EndRead returns –1.
Dim ar As IAsyncResult = responseStream.BeginRead( _
info.BufferRead, 0, BUFFER_SIZE, New AsyncCallback(AddressOf ReadCallBack), info)
Else
responseStream.Close()
allDone.Set()
End If
End Sub
End Class
End Namespace
''''''''''''''''''''''''''
Could someone help me debug this thing?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Test form:
Private WithEvents downloader As New RJH.Utils.WebDownload.WebD ownload
Private Sub downloader_DownloadProgres s(ByVal sender As Object, ByVal e As RJH.Utils.WebDownload.Down loadProgre ssEventArg s) Handles downloader.DownloadProgres s
Me.ProgressBar1.Minimum = 0
Me.ProgressBar1.Maximum = e.BytesTotal
Me.ProgressBar1.Value = e.BytesRead
Application.DoEvents()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
downloader.DownloadAsync(" http://www.microsoft.com/downloads/info.aspx?na=208&p=1&SrcDisplayLang=en&SrcCategoryId=&SrcFamilyId=435bfce7-da2b-4a6a-afa4-f7f14e605a0d&u=http%3a%2f%2fdownload.microsoft.com%2fdownload%2fe%2fd%2f0%2fed099d5e-dc60-4740-8747-1c72f053b800%2fWindowsDefender.msi")
End Sub
Private Sub downloader_DownloadComplet e(ByVal sender As Object, ByVal e As RJH.Utils.WebDownload.Down loadComple teEventArg s) Handles downloader.DownloadComplet e
MessageBox.Show("Length=" & e.Data.Length)
End Sub
Bob
Private WithEvents downloader As New RJH.Utils.WebDownload.WebD
Private Sub downloader_DownloadProgres
Me.ProgressBar1.Minimum = 0
Me.ProgressBar1.Maximum = e.BytesTotal
Me.ProgressBar1.Value = e.BytesRead
Application.DoEvents()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
downloader.DownloadAsync("
End Sub
Private Sub downloader_DownloadComplet
MessageBox.Show("Length=" & e.Data.Length)
End Sub
Bob
ASKER
Great code! It works! except the download is not started in a new thread.
I didn't have any problem with that. You can only have 2 downloads active at one time anyway.
Bob
Bob
1) Combined the two classes into 1.
2) Moved the main class 'WebDownload' to the top of the module.
3) Added event argument classes--DownloadProgressE
4) Removed the callbacks