2007. szeptember 22., szombat

How to download a file from the web to a local drive


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).

Nincsenek megjegyzések:

Megjegyzés küldése