Mirror

Download a file from the web to a local drive (Views: 101)

Problem/Question/Abstract:

I want to write an application that can download upgraded versions of itself.

Answer:

Solve 1:

If you are just going to download there is no need to use ActiveX controls. Windows has the function you need already declared in the UrlMon.dll. To download a file to a local disk just use this code. Note: This function is not described in Delphi Help nor in the Win32 Programmer's Reference.

uses
URLMon;

{ ... }
if URLDownloadToFile(nil, 'http://go.to/masdp', 'c:\index.html', 0, nil) <> 0 then
MessageBox(Handle, 'An error ocurred while downloading the file.', PChar(Application.Title), MB_ICONERROR or MB_OK);
{ ... }


Solve 2:

Downloading a file is not very difficult, something like:

uses
Wininet;

var
InternetBrowserUserAgent: string;
{Set it as you like. Win98/IE uses 'Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)' }

{ ... }

function GetInternetStream(URL: string; Stream: TStream): LongInt;
type
TNetBuffer = array[0..1023] of Byte;
PNetBuffer = ^TNetBuffer;
var
ihConnect, iDocument: HINTERNET;
NetBuffer: PNetBuffer;
BufferSize: Integer;
I: integer;
begin
Result := -1;
ihConnect := InternetOpen(PChar(InternetBrowserUserAgent), LOCAL_INTERNET_ACCESS, '', '', 0);
try
if ihConnect <> nil then
begin
iDocument := InternetOpenURL(ihConnect, PChar(URL), nil, Cardinal(-1),
INTERNET_FLAG_RELOAD or INTERNET_FLAG_DONT_CACHE or
INTERNET_FLAG_RAW_DATA, 0);
try
if iDocument <> nil then
begin
Result := 0;
try
New(NetBuffer);
repeat
InternetReadFile(iDocument, NetBuffer, SizeOf(TNetBuffer), BufferSize);
if BufferSize > 0 then
begin
Result := Result + Stream.Write(NetBuffer^, BufferSize);
end;
until
(BufferSize < SizeOf(TNetBuffer));
finally
Dispose(NetBuffer);
end;
end;
finally
internetCloseHandle(iDocument);
end;
end;
finally
InternetCloseHandle(ihConnect);
end;
end;

If you call this function with a TFileStream, you have the file on your harddisk. If you have a ZIP, you probably want to unzip the file now, use a component that can do this (I think there are some around). The problem is that an application cannot replace itself (because it is write protected while it is running). The solution would be to call another application and terminate the first one. The second one has to update the first one (maybe wait a while until it is really terminated and not write protect any more) and start it again. If you just have to update non-executable files this is much easier. Another solution would be a separate update-application, that the user can call from somewhere (after he has closed the main application).


Solve 3:

I always use this piece of code, works with proxy servers as well:

uses
WinInet;

var
BytesRead: DWord;
sUrl, S: string;
Nethandle, UrlHandle: Pointer;
M: TMemoryStream;
Buffer: array[0..8191] of Char;
begin
sUrl := 'http://.....';
NetHandle := InternetOpen('Mozilla 4.0', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
try
if Assigned(NetHandle) then
begin
UrlHandle := InternetOpenUrl(NetHandle, PChar(sUrl), nil, 0,
INTERNET_FLAG_RELOAD, 0);
if Assigned(UrlHandle) then
begin
M := TMemoryStream.Create;
try
repeat
FillChar(Buffer, SizeOf(Buffer), 0);
InternetReadFile(UrlHandle, @Buffer, SizeOf(Buffer), BytesRead);
if BytesRead > 0 then
M.Write(Buffer, BytesRead);
until
BytesRead = 0;
M.Position := 0;
SetLength(S, M.Size);
M.Read(S[1], M.Size);
InternetCloseHandle(UrlHandle);
M.Position := 0;
M.SaveToFile('..\Filename');
finally
M.Free;
end;
end;
end;
finally
InternetCloseHandle(NetHandle);
end;
end;



<< Back to main page