You can actually download files in VB without extra dependancy to anything. You don't even need a single API call. The only requirement is a user control.
Below is a simple sample that has the ability to download multiple files at once, and your application remains responsive as well. It keeps track of the given keys (or "PropertyNames") so you won't run into an error condition if you try to download a file while it is already being downloaded. The control will cancel the existing download when that same file is being tried to download again.
Public Event Complete(ByRef URL As String, ByRef Data As String, ByRef Key As String)
Public Event Progress(ByRef URL As String, ByRef Key As String, ByVal BytesDone As Long, ByVal BytesTotal As Long, ByVal Status As AsyncStatusCodeConstants)
Public Enum DownloaderCache
[Always download] = vbAsyncReadForceUpdate
[Get cache copy only] = vbAsyncReadOfflineOperation
[Update cached copy only] = vbAsyncReadResynchronize
[Use cache if no connection] = vbAsyncReadGetFromCacheIfNetFail
Private m_Keys As String
Private Function Private_AddKey(ByRef Key As String) As Boolean
' see if we do not have the key
Private_AddKey = InStr(m_Keys, vbNullChar & Key & vbNullChar) = 0
' we can add it
If Private_AddKey Then
m_Keys = m_Keys & Key & vbNullChar
Private Sub Private_RemoveKey(ByRef Key As String)
' remove the key
m_Keys = Replace(m_Keys, vbNullChar & Key & vbNullChar, vbNullChar)
Public Sub Start(ByRef URL As String, Optional ByVal CacheMode As DownloaderCache = [Always download], Optional ByVal Key As String)
' use URL as key if no key is given
If LenB(Key) = 0 Then Key = URL
' do we already have this key?
If Not Private_AddKey(Key) Then
' cancel the old one
' begin download process
AsyncRead URL, vbAsyncTypeByteArray, Key, CacheMode
Private Sub UserControl_AsyncReadComplete(AsyncProp As AsyncProperty)
Dim strData As String
' get Variant byte array to byte string (needs StrConv to Unicode for displaying in a textbox)
If AsyncProp.BytesRead Then strData = AsyncProp.Value Else strData = vbNullString
' redirect information
RaiseEvent Complete(AsyncProp.Target, strData, AsyncProp.PropertyName)
' remove the key
Private Sub UserControl_AsyncReadProgress(AsyncProp As AsyncProperty)
' redirect event information
If LenB(.PropertyName) Then
RaiseEvent Progress(.Target, .PropertyName, .BytesRead, .BytesMax, .StatusCode)
RaiseEvent Progress(.Target, vbNullString, .BytesRead, .BytesMax, .StatusCode)
Private Sub UserControl_Initialize()
m_Keys = vbNullChar
A sample application: you need two command buttons, one multiline textbox and a listbox. You need the user control as well.
You can also download images directly as a Picture object. To see other possible values, open up Object Browser with F2 and type Async into the search field.
Private Sub Command1_Click()
Private Sub Command2_Click()
Private Sub Downloader1_Complete(URL As String, Data As String, Key As String)
Me.Caption = URL
Text1.Text = StrConv(Data, vbUnicode)
Private Sub Downloader1_Progress(URL As String, Key As String, ByVal BytesDone As Long, ByVal BytesTotal As Long, ByVal Status As AsyncStatusCodeConstants)
List1.AddItem URL & " @ " & (BytesDone \ 1024) & " kB, status code: " & Status, 0
Showing a message box seems to entirely prevent events from triggering under the IDE. I haven't tested compiled, but I believe it works just fine there: timer events don't run in the IDE when a messagebox is shown, but compiled it works just fine.
2008-09-14: changed Data to string from byte array and made a check for if any data was received to avoid an error.