Download/Upload progress using RAS

  • Thread starter Thread starter TJoker .NET [MVP]
  • Start date Start date
T

TJoker .NET [MVP]

Hi folks.
In my application I have written code to connect to a private network using
RAS (RasDial, RasHangUp, etc) APIs.
After I'm connected and authenticated in the network, I'm able to send files
to a shared folder and read files from that same folder using code similar
to:
File.Copy("c:\myLocalFolder\file.ext",
"\\KnownServer\SharedFolder\file.ext")

My problem now is that these file copies (to and from the server) can take
couple of minutes for large files on dialup connections. So I need to show
some sort of progress bar to inform the user what percentage of the
transmission is done.

Does anyone knows how to get that kind of information from RAS or from the
File.Copy method ? Should I just try and use Streams instead and manage the
chunks of transmitted data myself ?

Thanks for any insight
 
OK. I think I answered my own question when I posted it.
I decided to use streams to copy the file chunk-by-chunk. I used a
delegate/event to give the calling code the work percent already done. The
calling code then figures out what is the bes way to show it. In my app the
best way was to put a ProgressBar in the StatusBar and update its value
according to the percentage.

Here's some preliminary code before I made the function
"ReportStatusBarProgress" an event or delegate.


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim fileSize As Integer
Dim src As FileStream
Dim dst As FileStream
Try
ShowStatusBarProgress()
src = New FileStream(srcFile, FileMode.Open)
dst = New FileStream(dstFile, FileMode.Create)

fileSize = src.Length
Debug.WriteLine("file size = " & fileSize)
Dim totalTransmitted As Integer = 0

Do While totalTransmitted < fileSize
Dim thisChunkSize As Integer = chunkSize
If (fileSize - totalTransmitted) < chunkSize Then
thisChunkSize = (fileSize - totalTransmitted)
Dim data(thisChunkSize - 1) As Byte

src.Read(data, 0, data.Length)
dst.Write(data, 0, data.Length)
totalTransmitted += thisChunkSize
Dim msg As String = String.Format("({1:P2}) Uploading file
{0}", System.IO.Path.GetFileName(srcFile), totalTransmitted / fileSize)

ReportStatusBarProgress(msg, CSng(totalTransmitted /
fileSize))

Debug.WriteLine("Wrote " & totalTransmitted & " of " &
fileSize & " bytes (" & (100 * totalTransmitted / fileSize) & "%)")
Loop

Catch ex As Exception
Debug.WriteLine("*** Exception: " & ex.Message & " [" &
ex.GetType().FullName & "]")
Finally
src.Close()
dst.Close()
HideStatusBarProgress()
End Try


End Sub

Private prgBar As ProgressBar
Private Sub ShowStatusBarProgress()
With StatusBar1
Dim pnl As New StatusBarPanel()
pnl.Width = 100
Dim messagePanelIndex As Integer = .Panels.IndexOf(.Panels(0))
.Panels.Insert(messagePanelIndex + 1, pnl)
.Panels(0).Width -= pnl.Width

.Panels(0).Text = ""
prgBar = New ProgressBar()
With prgBar
.Parent = StatusBar1
.Left = StatusBar1.Panels(0).Width +
SystemInformation.Border3DSize.Width
.Top = SystemInformation.Border3DSize.Height
.Width = 100 - SystemInformation.Border3DSize.Width
.Height = StatusBar1.Height -
SystemInformation.Border3DSize.Height

.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
.Refresh()

End With
.Refresh()

End With
End Sub

Private Sub HideStatusBarProgress()
prgBar.Hide()
prgBar.Parent = Nothing
prgBar.Dispose()
prgBar = Nothing
StatusBar1.Panels(0).Width += StatusBar1.Panels(1).Width
Dim messagePanelIndex As Integer =
StatusBar1.Panels.IndexOf(StatusBar1.Panels(0))
StatusBar1.Panels.RemoveAt(messagePanelIndex + 1)
StatusBar1.Refresh()
StatusBar1.Panels(0).Text = ""
End Sub

Private Sub ReportStatusBarProgress(ByVal message As String, ByVal
percentage As Single)
prgBar.Value = CInt(100 * percentage)
StatusBar1.Panels(0).Text = message
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
HideStatusBarProgress()
End Sub

--
TJoker, MCSD.NET
MVP: Paint, Notepad, Solitaire

****************************************
 
Oops, spoke too soon!
Just found out that when I connect through dialUp and try to copy the file,
the loop containing the dst.Write (stream.Write) is executed very fast and
all the way up to 100% of the bytes. THEN, when I close the stream the bytes
are sent to the remote folder. I even tried to put a dst.Flush() after the
dst.Write but it made no difference.
It seems like there's some "smart" code underneath that is buffering the
bytes befoer sending them to the remote folder.
Does anyone know how to make those bytes travel chunk-by-chunk ?
I'm considering using the API CopyFileEx for this...

Thanks

--
TJoker, MCSD.NET
MVP: Paint, Notepad, Solitaire

****************************************


TJoker .NET said:
OK. I think I answered my own question when I posted it.
I decided to use streams to copy the file chunk-by-chunk. I used a
delegate/event to give the calling code the work percent already done. The
calling code then figures out what is the bes way to show it. In my app the
best way was to put a ProgressBar in the StatusBar and update its value
according to the percentage.

Here's some preliminary code before I made the function
"ReportStatusBarProgress" an event or delegate.


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim fileSize As Integer
Dim src As FileStream
Dim dst As FileStream
Try
ShowStatusBarProgress()
src = New FileStream(srcFile, FileMode.Open)
dst = New FileStream(dstFile, FileMode.Create)

fileSize = src.Length
Debug.WriteLine("file size = " & fileSize)
Dim totalTransmitted As Integer = 0

Do While totalTransmitted < fileSize
Dim thisChunkSize As Integer = chunkSize
If (fileSize - totalTransmitted) < chunkSize Then
thisChunkSize = (fileSize - totalTransmitted)
Dim data(thisChunkSize - 1) As Byte

src.Read(data, 0, data.Length)
dst.Write(data, 0, data.Length)
totalTransmitted += thisChunkSize
Dim msg As String = String.Format("({1:P2}) Uploading file
{0}", System.IO.Path.GetFileName(srcFile), totalTransmitted / fileSize)

ReportStatusBarProgress(msg, CSng(totalTransmitted /
fileSize))

Debug.WriteLine("Wrote " & totalTransmitted & " of " &
fileSize & " bytes (" & (100 * totalTransmitted / fileSize) & "%)")
Loop

Catch ex As Exception
Debug.WriteLine("*** Exception: " & ex.Message & " [" &
ex.GetType().FullName & "]")
Finally
src.Close()
dst.Close()
HideStatusBarProgress()
End Try


End Sub

Private prgBar As ProgressBar
Private Sub ShowStatusBarProgress()
With StatusBar1
Dim pnl As New StatusBarPanel()
pnl.Width = 100
Dim messagePanelIndex As Integer = .Panels.IndexOf(.Panels(0))
.Panels.Insert(messagePanelIndex + 1, pnl)
.Panels(0).Width -= pnl.Width

.Panels(0).Text = ""
prgBar = New ProgressBar()
With prgBar
.Parent = StatusBar1
.Left = StatusBar1.Panels(0).Width +
SystemInformation.Border3DSize.Width
.Top = SystemInformation.Border3DSize.Height
.Width = 100 - SystemInformation.Border3DSize.Width
.Height = StatusBar1.Height -
SystemInformation.Border3DSize.Height

.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
.Refresh()

End With
.Refresh()

End With
End Sub

Private Sub HideStatusBarProgress()
prgBar.Hide()
prgBar.Parent = Nothing
prgBar.Dispose()
prgBar = Nothing
StatusBar1.Panels(0).Width += StatusBar1.Panels(1).Width
Dim messagePanelIndex As Integer =
StatusBar1.Panels.IndexOf(StatusBar1.Panels(0))
StatusBar1.Panels.RemoveAt(messagePanelIndex + 1)
StatusBar1.Refresh()
StatusBar1.Panels(0).Text = ""
End Sub

Private Sub ReportStatusBarProgress(ByVal message As String, ByVal
percentage As Single)
prgBar.Value = CInt(100 * percentage)
StatusBar1.Panels(0).Text = message
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
HideStatusBarProgress()
End Sub

--
TJoker, MCSD.NET
MVP: Paint, Notepad, Solitaire

****************************************


TJoker .NET said:
Hi folks.
In my application I have written code to connect to a private network using
RAS (RasDial, RasHangUp, etc) APIs.
After I'm connected and authenticated in the network, I'm able to send files
to a shared folder and read files from that same folder using code similar
to:
File.Copy("c:\myLocalFolder\file.ext",
"\\KnownServer\SharedFolder\file.ext")

My problem now is that these file copies (to and from the server) can take
couple of minutes for large files on dialup connections. So I need to show
some sort of progress bar to inform the user what percentage of the
transmission is done.

Does anyone knows how to get that kind of information from RAS or from the
File.Copy method ? Should I just try and use Streams instead and manage the
chunks of transmitted data myself ?

Thanks for any insight

--
TJoker, MCSD.NET
MVP: Paint, Notepad, Solitaire

****************************************
 
Ok. It seems that I'm feeding my own thread :)
I'll keep posting progress hoping that it can help someone another day.

After not being able to spend time trying to figure out why Stream.Write +
Stream.Flush() was not saving the data to the device I decided to give the
CopyFileEx API a go.
It worked much better! It provides me with progress callback. The only
downside it that it seems to tranmit the data in fixed sized chunks (64Kb
for local copies and ~61K for network copies) and I couldn't find a way to
change those sizes.
What is happening now is that when I copy a file of say 100K to a network
folder, using dialup, it takes around 30 seconds but the application can
only refresh the progress bar twice (one at ~61K transmitted, and the other
upon completion), so the progress bar goes 0% --> 55% --> 100%, waiting for
around 15 seconds between each update.
All in all, it is an improvement and I think that this is the way I'll gave
to go with until somebody officially complains.

Here's some code for your pleasure :)

Public Delegate Function CopyProgressRoutine( _
ByVal TotalFileSize As Int64, _
ByVal TotalBytesTransferred As Int64, _
ByVal StreamSize As Int64, _
ByVal StreamBytesTransferred As Int64, _
ByVal dwStreamNumber As Int32, _
ByVal dwCallbackReason As Int32, _
ByVal hSourceFile As Int32, _
ByVal hDestinationFile As Int32, _
ByVal lpData As Int32 _
) As Int32

Declare Auto Function CopyFileEx Lib "kernel32.dll" ( _
ByVal lpExistingFileName As String, _
ByVal lpNewFileName As String, _
ByVal lpProgressRoutine As CopyProgressRoutine, _
ByVal lpData As Int32, _
ByVal lpBool As Int32, _
ByVal dwCopyFlags As Int32 _
) As Int32

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button3.Click
CopyFileEx("c:\fileTest.dat", "\\server123\share123\fileTest.dat", New
CopyProgressRoutine(AddressOf myProgress), 0, 0, 0)
End Sub

Private Sub ReportStatusBarProgress(ByVal message As String, ByVal
percentage As Single)
progrBar.Value = CInt(progrBar.Maximum * percentage)
progrBar.Invalidate()
statusBar1.Panels(0).Text = message
statusBar1.Invalidate()
End Sub

Private Function myProgress( _
ByVal TotalFileSize As Int64, _
ByVal TotalBytesTransferred As Int64, _
ByVal StreamSize As Int64, _
ByVal StreamBytesTransferred As Int64, _
ByVal dwStreamNumber As Int32, _
ByVal dwCallbackReason As Int32, _
ByVal hSourceFile As Int32, _
ByVal hDestinationFile As Int32, _
ByVal lpData As Int32) As Integer

Dim msg As String = String.Format("({0:P2}) Uploading file",
TotalBytesTransferred / TotalFileSize)

ReportStatusBarProgress(msg, CSng(TotalBytesTransferred / TotalFileSize))
End Function


--
TJoker, MCSD.NET
MVP: Paint, Notepad, Solitaire

****************************************


TJoker .NET said:
Oops, spoke too soon!
Just found out that when I connect through dialUp and try to copy the file,
the loop containing the dst.Write (stream.Write) is executed very fast and
all the way up to 100% of the bytes. THEN, when I close the stream the bytes
are sent to the remote folder. I even tried to put a dst.Flush() after the
dst.Write but it made no difference.
It seems like there's some "smart" code underneath that is buffering the
bytes befoer sending them to the remote folder.
Does anyone know how to make those bytes travel chunk-by-chunk ?
I'm considering using the API CopyFileEx for this...

Thanks

--
TJoker, MCSD.NET
MVP: Paint, Notepad, Solitaire

****************************************


TJoker .NET said:
OK. I think I answered my own question when I posted it.
I decided to use streams to copy the file chunk-by-chunk. I used a
delegate/event to give the calling code the work percent already done. The
calling code then figures out what is the bes way to show it. In my app the
best way was to put a ProgressBar in the StatusBar and update its value
according to the percentage.

Here's some preliminary code before I made the function
"ReportStatusBarProgress" an event or delegate.


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim fileSize As Integer
Dim src As FileStream
Dim dst As FileStream
Try
ShowStatusBarProgress()
src = New FileStream(srcFile, FileMode.Open)
dst = New FileStream(dstFile, FileMode.Create)

fileSize = src.Length
Debug.WriteLine("file size = " & fileSize)
Dim totalTransmitted As Integer = 0

Do While totalTransmitted < fileSize
Dim thisChunkSize As Integer = chunkSize
If (fileSize - totalTransmitted) < chunkSize Then
thisChunkSize = (fileSize - totalTransmitted)
Dim data(thisChunkSize - 1) As Byte

src.Read(data, 0, data.Length)
dst.Write(data, 0, data.Length)
totalTransmitted += thisChunkSize
Dim msg As String = String.Format("({1:P2}) Uploading file
{0}", System.IO.Path.GetFileName(srcFile), totalTransmitted / fileSize)

ReportStatusBarProgress(msg, CSng(totalTransmitted /
fileSize))

Debug.WriteLine("Wrote " & totalTransmitted & " of " &
fileSize & " bytes (" & (100 * totalTransmitted / fileSize) & "%)")
Loop

Catch ex As Exception
Debug.WriteLine("*** Exception: " & ex.Message & " [" &
ex.GetType().FullName & "]")
Finally
src.Close()
dst.Close()
HideStatusBarProgress()
End Try


End Sub

Private prgBar As ProgressBar
Private Sub ShowStatusBarProgress()
With StatusBar1
Dim pnl As New StatusBarPanel()
pnl.Width = 100
Dim messagePanelIndex As Integer = ..Panels.IndexOf(.Panels(0))
.Panels.Insert(messagePanelIndex + 1, pnl)
.Panels(0).Width -= pnl.Width

.Panels(0).Text = ""
prgBar = New ProgressBar()
With prgBar
.Parent = StatusBar1
.Left = StatusBar1.Panels(0).Width +
SystemInformation.Border3DSize.Width
.Top = SystemInformation.Border3DSize.Height
.Width = 100 - SystemInformation.Border3DSize.Width
.Height = StatusBar1.Height -
SystemInformation.Border3DSize.Height

.Minimum = 0
.Maximum = 100
.Value = 0
.Visible = True
.Refresh()

End With
.Refresh()

End With
End Sub

Private Sub HideStatusBarProgress()
prgBar.Hide()
prgBar.Parent = Nothing
prgBar.Dispose()
prgBar = Nothing
StatusBar1.Panels(0).Width += StatusBar1.Panels(1).Width
Dim messagePanelIndex As Integer =
StatusBar1.Panels.IndexOf(StatusBar1.Panels(0))
StatusBar1.Panels.RemoveAt(messagePanelIndex + 1)
StatusBar1.Refresh()
StatusBar1.Panels(0).Text = ""
End Sub

Private Sub ReportStatusBarProgress(ByVal message As String, ByVal
percentage As Single)
prgBar.Value = CInt(100 * percentage)
StatusBar1.Panels(0).Text = message
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
HideStatusBarProgress()
End Sub

--
TJoker, MCSD.NET
MVP: Paint, Notepad, Solitaire

****************************************


TJoker .NET said:
Hi folks.
In my application I have written code to connect to a private network using
RAS (RasDial, RasHangUp, etc) APIs.
After I'm connected and authenticated in the network, I'm able to send files
to a shared folder and read files from that same folder using code similar
to:
File.Copy("c:\myLocalFolder\file.ext",
"\\KnownServer\SharedFolder\file.ext")

My problem now is that these file copies (to and from the server) can take
couple of minutes for large files on dialup connections. So I need to show
some sort of progress bar to inform the user what percentage of the
transmission is done.

Does anyone knows how to get that kind of information from RAS or from the
File.Copy method ? Should I just try and use Streams instead and
manage
the
chunks of transmitted data myself ?

Thanks for any insight

--
TJoker, MCSD.NET
MVP: Paint, Notepad, Solitaire

****************************************
 
Back
Top