Downloading+a+file+from+a+URL

//by Richard Russell, August 2007; amended July 2009//

The simplest method of downloading a file (e.g. a web page) from an internet URL is to use the **URLDownloadToFile** API function as described in the main [|documentation]. The following program segment illustrates how to do that:

code format="bb4w" url$ = "http://www.bbcbasic.co.uk/bbcwin/bbcwin.html" file$ = @tmp$+"bbcwin.html" PROCurldownload(url$, file$) END

DEF PROCurldownload(url$, file$) LOCAL urlmon%, res% SYS "LoadLibrary", "urlmon.dll" TO urlmon% SYS "GetProcAddress", urlmon%, "URLDownloadToFileA" TO `URLDownloadToFile` SYS `URLDownloadToFile`, 0, url$, file$, 0, 0 TO res% SYS "FreeLibrary", urlmon% IF res% ERROR 100, "Couldn't download "+url$ ENDPROC code If you need to flush the cache to ensure you retrieve the latest version (e.g. it's a webcam picture) then it becomes slightly more complicated:

code format="bb4w" url$ = "http://www.bbcbasic.co.uk/bbcwin/bbcwin.html" file$ = @tmp$+"bbcwin.html" PROCurldownloadflush(url$, file$) END

DEF PROCurldownloadflush(url$, file$) LOCAL urlmon%, wininet%, res% SYS "LoadLibrary", "URLMON.DLL" TO urlmon% SYS "GetProcAddress", urlmon%, "URLDownloadToFileA" TO `URLDownloadToFile` SYS "LoadLibrary", "WININET.DLL" TO wininet% SYS "GetProcAddress", wininet%, "DeleteUrlCacheEntryA" TO `DeleteUrlCacheEntry` SYS `DeleteUrlCacheEntry`, url$ SYS `URLDownloadToFile`, 0, url$, file$, 0, 0 TO res% SYS "FreeLibrary", wininet% SYS "FreeLibrary", urlmon% IF res% ERROR 100, "Couldn't download "+url$ ENDPROC code These routines can be used for both **HTTP** and **FTP** downloads.

However under some circumstances the above methods do not work reliably. In that case you may find the following routine to be more successful:

code format="bb4w" url$ = "http://www.bbcbasic.co.uk/bbcwin/bbcwin.html" file$ = @tmp$+"bbcwin.html" PROCurldownload(url$, file$) END

DEF PROCurldownload(url$, file$) LOCAL wininet%, buffer%, hinet%, hreq%, file%, nbr%, nbw%, ok% DIM buffer% LOCAL 511 _INTERNET_OPEN_TYPE_PRECONFIG = 0 _INTERNET_FLAG_RELOAD = &80000000 SYS "LoadLibrary", "WININET.DLL" TO wininet% SYS "GetProcAddress", wininet%, "InternetOpenA"      TO `InternetOpen` SYS "GetProcAddress", wininet%, "InternetOpenUrlA"   TO `InternetOpenUrl` SYS "GetProcAddress", wininet%, "InternetReadFile"   TO `InternetReadFile` SYS "GetProcAddress", wininet%, "InternetCloseHandle" TO `InternetCloseHandle` SYS `InternetOpen`, "BB4W", _INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0 TO hinet% IF hinet% = 0 ERROR 100, "Couldn't open internet services" SYS `InternetOpenUrl`, hinet%, url$, "", 0, _INTERNET_FLAG_RELOAD, 0 TO hreq% IF hreq% = 0 THEN PROCinetcleanup ERROR 100, "Couldn't open "+url$ ENDIF file% = OPENOUT(file$) IF file% = 0 THEN PROCinetcleanup ERROR 100, "Couldn't create "+file$ ENDIF REPEAT SYS `InternetReadFile`, hreq%, buffer%, 512, ^nbr% TO ok% IF ok% = 0 THEN PROCinetcleanup ERROR 100, "Couldn't read from "+url$ ENDIF SYS "WriteFile", @hfile%(file%), buffer%, nbr%, ^nbw%, 0 TO ok% IF ok% = 0 THEN PROCinetcleanup ERROR 100, "Couldn't write "+file$ ENDIF UNTIL nbr% = 0 CLOSE #file% PROCinetcleanup ENDPROC DEF PROCinetcleanup hreq% += 0 : IF hreq%  SYS `InternetCloseHandle`, hreq%  : hreq% = 0 hinet% += 0 : IF hinet% SYS `InternetCloseHandle`, hinet% : hinet% = 0 wininet% += 0 : IF wininet% SYS "FreeLibrary", wininet% : wininet% = 0 ENDPROC code Unfortunately with early versions of Internet Explorer (pre 4.0) the above code results in a memory leak when used for **http** downloads (see []). If you need your code to work with such old versions you can use the following routine instead (note that because the HTTP protocol is implied, you must **not** include the **** in the supplied **server$**):

code format="bb4w" server$ = "www.bbcbasic.co.uk" request$ = "bbcwin/bbcwin.html" file$ = @tmp$+"bbcwin.html" PROChttpdownload(server$, request$, file$) END DEF PROChttpdownload(server$, request$, file$) LOCAL wininet%, buffer%, hinet%, hsess%, hreq%, file%, nbr%, nbw%, ok% DIM buffer% LOCAL 511 _INTERNET_OPEN_TYPE_PRECONFIG = 0 _INTERNET_DEFAULT_HTTP_PORT = 80 _INTERNET_SERVICE_HTTP = 3 _INTERNET_FLAG_RELOAD = &80000000 SYS "LoadLibrary", "WININET.DLL" TO wininet% SYS "GetProcAddress", wininet%, "InternetOpenA"      TO `InternetOpen` SYS "GetProcAddress", wininet%, "InternetConnectA"   TO `InternetConnect` SYS "GetProcAddress", wininet%, "HttpOpenRequestA"   TO `HttpOpenRequest` SYS "GetProcAddress", wininet%, "HttpSendRequestA"   TO `HttpSendRequest` SYS "GetProcAddress", wininet%, "InternetReadFile"   TO `InternetReadFile` SYS "GetProcAddress", wininet%, "InternetCloseHandle" TO `InternetCloseHandle` SYS `InternetOpen`, "BB4W", _INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0 TO hinet% IF hinet% = 0 ERROR 100, "Couldn't open internet services" SYS `InternetConnect`, hinet%, server$, _INTERNET_DEFAULT_HTTP_PORT, \ \                     "", "", _INTERNET_SERVICE_HTTP, 0, 0 TO hsess% IF hsess% = 0 THEN PROCinetcleanup ERROR 100, "Couldn't connect to "+server$ ENDIF SYS `HttpOpenRequest`, hsess%, 0, request$, 0, 0, 0, _INTERNET_FLAG_RELOAD, \ \                     0 TO hreq% IF hreq% = 0 THEN PROCinetcleanup ERROR 100, "Couldn't open "+request$ ENDIF SYS `HttpSendRequest`, hreq%, 0, 0, 0, 0 TO ok% IF ok% = 0 THEN PROCinetcleanup ERROR 100, "Couldn't request "+request$ ENDIF file% = OPENOUT(file$) IF file% = 0 THEN PROCinetcleanup ERROR 100, "Couldn't create "+file$ ENDIF REPEAT SYS `InternetReadFile`, hreq%, buffer%, 512, ^nbr% TO ok% IF ok% = 0 THEN PROCinetcleanup ERROR 100, "Couldn't read "+request$ ENDIF SYS "WriteFile", @hfile%(file%), buffer%, nbr%, ^nbw%, 0 TO ok% IF ok% = 0 THEN PROCinetcleanup ERROR 100, "Couldn't write "+file$ ENDIF UNTIL nbr% = 0 CLOSE #file% PROCinetcleanup ENDPROC DEF PROCinetcleanup hreq% += 0 : IF hreq%  SYS `InternetCloseHandle`, hreq%  : hreq% = 0 hsess% += 0 : IF hsess% SYS `InternetCloseHandle`, hsess% : hsess% = 0 hinet% += 0 : IF hinet% SYS `InternetCloseHandle`, hinet% : hinet% = 0 wininet% += 0 : IF wininet% SYS "FreeLibrary", wininet% : wininet% = 0 ENDPROC code