Web Binary Download Methods


Here is the "usual" method of performing a binary download over HTTP. It tries four different binary download capable objects, and has two separate methods for saving the binary to disk. Fairly bulletproof:


Function SaveWebBinary(strUrl, strFile) 'As Boolean
Const adTypeBinary = 1
Const adSaveCreateOverWrite = 2
Const ForWriting = 2
Dim web, varByteArray, strData, strBuffer, lngCounter, ado
On Error Resume Next
'Download the file with any available object
Err.Clear
Set web = Nothing
Set web = CreateObject("WinHttp.WinHttpRequest.5.1")
If web Is Nothing Then Set web = CreateObject("WinHttp.WinHttpRequest")
If web Is Nothing Then Set web = CreateObject("MSXML2.ServerXMLHTTP")
If web Is Nothing Then Set web = CreateObject("Microsoft.XMLHTTP")
web.Open "GET", strURL, False
web.Send
If Err.Number <> 0 Then
SaveWebBinary = False
Set web = Nothing
Exit Function
End If
If web.Status <> "200" Then
SaveWebBinary = False
Set web = Nothing
Exit Function
End If
varByteArray = web.ResponseBody
Set web = Nothing
'Now save the file with any available method
On Error Resume Next
Set ado = Nothing
Set ado = CreateObject("ADODB.Stream")
If ado Is Nothing Then
Set fs = CreateObject("Scripting.FileSystemObject")
Set ts = fs.OpenTextFile(strFile, ForWriting, True)
strData = ""
strBuffer = ""
For lngCounter = 0 to UBound(varByteArray)
ts.Write Chr(255 And Ascb(Midb(varByteArray,lngCounter + 1, 1)))
Next
ts.Close
Else
ado.Type = adTypeBinary
ado.Open
ado.Write varByteArray
ado.SaveToFile strFile, adSaveCreateOverWrite
ado.Close
End If
SaveWebBinary = True
End Function




I was playing around and found other ways you can misuse the system to do a binary download!


WSC file:

You don't have to register WSC files. Instead, you can specify their location in your script. You can even specify an HTTP location. The file is downloaded automatically and ends up in your IE cache. If you specify something other than a real WSC file as the target, it gets downloaded and run as a script. Which is gonna throw an error! So you just block the error:

On Error Resume Next
GetObject "script:http://www.ericphelps.com/image/logo1.gif"


The code above is ordinary VBS code. Nothing to do with WSC files except that the "GetObject" method with the "script:" protocol is NORMALLY used to get a WSC file. We use it here to get something else. The above VBS code will download a graphic from my web page and drop it in the IE cache. To locate the file in the cache, use code similar to this:

Function FindInCache(strFile)
'Supply a file name only (no path) and it will return the
'full path and file to the file's first located cache location.
'If the file is not found, an empty string will be returned.
Dim wsh, fso, strFileName, strFilePath
strFileName = strFile
Set fso = CreateObject("Scripting.FileSystemObject")
Set wsh = CreateObject("Wscript.Shell")
'Cache files generally have "[1]" inserted just before the file extension.
If InStr(strFileName, "].") = 0 Then
strFileName = Left(strFileName, InStrRev(strFileName, ".") - 1) & "[1]" & Mid(strFileName, InStrRev(strFileName, "."))
End If
'Start building the file path by getting the basic path
strFilePath = wsh.Environment("PROCESS")("USERPROFILE")
strFilePath = strFilePath & "\Local Settings\Temporary Internet Files\"
'Now search the possible paths for the desired file
strFilePath = SearchForFile(fso.GetFolder(strFilePath), strFileName)
'Return the result
FindInCache = strFilePath
End Sub

Function SearchForFile(objFolder, strFile)
Dim fils, fil, fols, fol, strFilePath
'Check all the files in the current folder
On Error Resume Next
Set fils = objFolder.Files
If Err.Number = 0 Then
For Each fil In fils
If fil.Name = strFile Then
SearchForFile = fil.Path
Exit Function
End If
Next
End If
'Check for any sub folders and recursively search them
Set fols = objFolder.SubFolders
For each fol in fols
strFilePath = ""
strFilePath = SearchForFile(fol, strFile)
If strFilePath <> "" Then
SearchForFile = strFilePath
Exit Function
End If
Next
SearchForFile = strFilePath
End Function


In real life, you'd want to search the cache FIRST, delete any matches you found, then download the file you wanted. Then whatever you find in the cache is sure to be what you want.



WSF file:
If you write your VBS code in WSH files instead of in VBS files, you get to specify a lot more options. Including where to get external code:

<job>
<script language="vbscript" src="http://www.ericphelps.com/image/logo1.gif"/>
</job>


Unfortunately, this crashes the entire WSF file, so you need to have your VBS file create or use a WSF file like the one above and run it with wsh.Run or wsh.Exec so your mainline code will survive. Try something like this VBS code:

Dim wsh, fso, ts
Const TEMP_FILE = "C:\~temp.wsf"
Set wsh = CreateObject("Wscript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.OpenTextFile(TEMP_FILE, 2, True)
ts.WriteLine "<job>"
ts.WriteLine "<script language=""vbscript"" "
ts.WriteLine "src=""http://www.ericphelps.com/image/logo1.gif""/>"
ts.WriteLine "</job>"
ts.Close
wsh.Run "cscript.exe " & TEMP_FILE, 0, True
fso.DeleteFile TEMP_FILE

It's important that the wsh.Run happen with CSCRIPT.EXE as the running engine and that it run with zero as the window type. When the WSF file throws it's error, if the engine was wscript, it would pop up an error dialog. That's bad. By using the cscript engine, the error just gets written in the DOS box. And by setting the window type to zero, nobody even sees the DOS box. And sure enough, the file "logo1.gif" would appear in your IE cache.

Again, once the file is in you cache, use code similar to the "FindInCache" and "SearchForFile" functions I showed above to mentioned above to locate your file.