Link to home
Start Free TrialLog in
Avatar of BadBigShot
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(ByVal 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(downloadedData)
            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(ByVal 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.ArrayList

        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.Count) {}

                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-Length")
            If strContentLength <> 0 Then
                info.dataLength = Convert.ToInt32(strContentLength)
                info.dataBufferFast = New Byte(info.dataLength) {}
            Else
                info.useFastBuffers = False
                info.dataBufferSlow = New System.Collections.ArrayList(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(info.BufferRead, 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(asyncResult)
            If bytesRead > 0 Then
                If info.useFastBuffers Then
                    System.Array.Copy(info.BufferRead, 0, info.dataBufferFast, info.bytesProcessed, bytesRead)
                Else
                    For b = 0 To bytesRead - 1
                        info.dataBufferSlow.Add(info.BufferRead(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.bytesProcessed, 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?
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Notes:

1) Combined the two classes into 1.
2) Moved the main class 'WebDownload' to the top of the module.
3) Added event argument classes--DownloadProgressEventArgs and DownloadCompleteEventArgs
4) Removed the callbacks
Test form:

  Private WithEvents downloader As New RJH.Utils.WebDownload.WebDownload

  Private Sub downloader_DownloadProgress(ByVal sender As Object, ByVal e As RJH.Utils.WebDownload.DownloadProgressEventArgs) Handles downloader.DownloadProgress
    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_DownloadComplete(ByVal sender As Object, ByVal e As RJH.Utils.WebDownload.DownloadCompleteEventArgs) Handles downloader.DownloadComplete

    MessageBox.Show("Length=" & e.Data.Length)

  End Sub

Bob
Avatar of BadBigShot
BadBigShot

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