Search code examples
windowsdelphi

How to retrieve a file from Internet via HTTP?


I want to download a file from Internet and InternetReadFile seem a good and easy solution at the first glance. Actually, too good to be true. Problems could appear because:

  • the application freezes temporarily until the HTTP server responds
  • the application freezes temporarily because the Internet connections breaks
  • the application locks up because the HTTP server never responds
  • the InternetOpen (I just discovered this recently) MUST be called only once during application life time

I could not find a complete example about how to use it properly and robustly. Does anybody have an idea about how to implement it in a separate thread and with a time out?

There is another SIMPLE way to robustly download a file from Internet:

function GetFileHTTP (const fileURL, FileName: String): boolean;
CONST
  BufferSize = 1024;
VAR
  hSession, hURL: HInternet;
  Buffer: array[1..BufferSize] of Byte;
  BufferLen: DWORD;
  f: File;
  sAppName: string;
begin
//  result := false;
 sAppName := ExtractFileName(Application.ExeName) ;
 hSession := InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0) ;  { be aware that InternetOpen  need only be called once in your application!!!!!!!!!!!!!! }
 TRY
  hURL := InternetOpenURL(hSession, PChar(fileURL), nil, 0, 0, 0) ;
  TRY
   AssignFile(f, FileName) ;
   Rewrite(f, 1) ;
   REPEAT
    InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen);
    BlockWrite(f, Buffer, BufferLen)
   UNTIL BufferLen = 0;
   CloseFile(f) ;
   Result:= True;
  FINALLY
   InternetCloseHandle(hURL)
  end
 FINALLY
  InternetCloseHandle(hSession)
 END;
END;

Edit:
This functions checks if Internet connection is available. It seems to work on Win98 also.

{  Are we connected to the Internet? }
function IsConnectedToInternet: Boolean;                                        { Call SHELL32.DLL for Win < Win98 otherwise call URL.dll }
var InetIsOffline: function(dwFlags: DWORD): BOOL; stdcall;
begin
 Result:= FALSE;
 if IsApiFunctionAvailable('URL.DLL', 'InetIsOffline', @InetIsOffline)
 then Result:= NOT InetIsOffLine(0)
 else
   if IsApiFunctionAvailable('SHELL32.DLL', 'InetIsOffline', @InetIsOffline)
   then Result:= NOT InetIsOffLine(0)
end;

Edit:

Writing your code to be Microsoft platform dependent is bad. You never know if the customer has the IE version x.x installed.

Installing stuff into a user's computer is like playing with guns. It will backfire.

(see more about this here: http://thesunstroke.blogspot.com/2010/06/programmig-like-there-is-no-ms-windows.html)


Solution

  • Solved using improved version of the above code. (it still does not solve all issues - MS does not actually implemented full support for server time out)

    The connection does not timeout while downloading file from internet