Solved

Downloding a file with Internet Explorer

Posted on 1998-07-01
10
615 Views
Last Modified: 2012-06-27
How can I download a file with Internet Explorer through Delphi program and how can I detect the file is downloded?
0
Comment
Question by:fh1
  • 6
  • 3
10 Comments
 
LVL 4

Expert Comment

by:d003303
ID: 1356820
Yo,
this code uses the internet functions provided with IExplorer. It uses the HTTPProt unit from F. Piette for Base64-encoding of the User/Password combination. Get it at
http://www.rtfm.be/fpiette

// helper unit
unit url_req;

interface

uses Classes, Windows, WinInet;

const TheUserAgent = 'Slash-Agent';

// initialize all values
procedure WinInetInit;

// uninitialize all values
procedure WinInetUnInit;

// get httpdata in stream
procedure WinInetGetDataFromURL(URL, User, Password : string; AStream : TMemoryStream);

implementation

uses SysUtils, HTTPProt;

var
    FInetSessionHandle,
    FConnectionHandle  : HINTERNET;

procedure WinInetInit;
begin
  // use default settings from registry
  FInetSessionHandle := InternetOpen(TheUserAgent, INTERNET_OPEN_TYPE_PRECONFIG,
                                nil, nil, 0);
end;

procedure WinInetUnInit;
begin
  InternetCloseHandle(FInetSessionHandle);
end;

procedure WinInetGetDataFromURL(URL, User, Password : string; AStream : TMemoryStream);
const BufSize          = 1024;
      Terminator: Byte = $00;
var ReadResult         : Boolean;
    CanonicalizeURLSize,
    BytesRead          : DWord;
    FAddHeader         : string;
    Buffer             : array[0..(BufSize - 1)] of Char;
    FURL               : array[0..INTERNET_MAX_URL_LENGTH] of Char;
    FSessionContext    : DWord;
begin
  FSessionContext := 0;
  if User <> ''
   then FAddHeader := 'Authorization: Basic ' + EncodeBase64(User + ':' + Password);

  if FInetSessionHandle = nil
   then raise Exception.Create('Invalid session handle');

  CanonicalizeURLSize := INTERNET_MAX_URL_LENGTH + 1;
  if InternetCanonicalizeURL(PChar(URL), FURL, CanonicalizeURLSize, 0) = false
   then raise Exception.Create('InternetCanonicalizeURL Error code ' + IntToStr(GetLastError));

  FConnectionHandle := InternetOpenURL(FInetSessionHandle, FURL, PChar(FAddHeader), Length(FAddHeader), INTERNET_FLAG_RELOAD or INTERNET_FLAG_RAW_DATA, FSessionContext);

  if FConnectionHandle = nil
   then raise Exception.Create('InternetOpenURL Error code ' + IntToStr(GetLastError));

  try
    // read data
    repeat
      ReadResult := InternetReadFile(FConnectionHandle, @Buffer[0], BufSize, BytesRead);
      if ReadResult = false
       then Break;
      AStream.SetSize(AStream.Size + BytesRead);
      AStream.Write(Buffer[0], BytesRead);
    until BytesRead = 0;
    AStream.SetSize(AStream.Size + 1);
    AStream.Write(Terminator, 1);
  finally
    InternetCloseHandle(FConnectionHandle);
  end;
end;

end.

// sample: place a memo, a button and an edit field on a form. Include url_req in your uses-clause and add this code to the OnClick handler of the button:

procedure TForm1.Button1Click(Sender: TObject);
var AStream : TMemoryStream;
    TheURL  : string;
begin
  if Edit1.Text = ''
   then Exit;
  Memo1.Clear;
  AStream := TMemoryStream.Create;
  try
    TheURL := Edit1.Text;
    WinInetGetDataFromURL(TheURL, '', '', AStream);
    Memo1.SetSelTextBuf(AStream.Memory);
  finally
    AStream.Free;
  end;
end;

You can use the WinInetGetDataFromURL function for any kind of protocol (ftp, gopher, http, https) and file type.

Slash/d003303
0
 
LVL 4

Expert Comment

by:d003303
ID: 1356821
oops, i forgot: you also need to assign this code to the forms OnCreate and OnDestroy handlers:

procedure TForm1.FormCreate(Sender: TObject);
begin
  WinInetInit;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  WinInetUnInit;
end;

Slash/d003303
0
 

Author Comment

by:fh1
ID: 1356822
Please add comments to your code so I can understand it.
0
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 7

Expert Comment

by:jconde
ID: 1356823
fh1, there's a Freeware Internet Suite with source code Included that has an example on how to download a file via http.

Please download this suite, install it, and check the http examples out!

bye
jorge

URL:  http://www.rtfm.be/fpiette/indexuk.htm
0
 
LVL 4

Expert Comment

by:d003303
ID: 1356824
Sure, I add comments. Please re-open the question first.

Slash/d003303
0
 
LVL 4

Accepted Solution

by:
d003303 earned 200 total points
ID: 1356825
unit url_req;

interface

uses Classes, Windows, WinInet;

// UserAgent: This identifies the requesting client to the server. Mostly needed for request logging reasons.
// E.g. Netscape uses 'Mozilla'
const TheUserAgent = 'Slash-Agent';

// initialize all values
procedure WinInetInit;

// uninitialize all values
procedure WinInetUnInit;

// get httpdata in stream
procedure WinInetGetDataFromURL(URL, User, Password : string; AStream : TMemoryStream);

implementation

uses SysUtils, HTTPProt;

var
    FInetSessionHandle,
    FConnectionHandle  : HINTERNET;

procedure WinInetInit;
begin
  // use default settings from registry
  // InternetOpen initializes a session. Sessions remember e.g.
  // proxy and server passwords, current location for relative URLs etc.
  // INTERNET_OPEN_TYPE_PRECONFIG means that this session will
  // take the same session parameters as Internet Explorer does on startup.
  // the function returns a session handle (unique identifier) that is stored in a global variable in this case.
  FInetSessionHandle := InternetOpen(TheUserAgent, INTERNET_OPEN_TYPE_PRECONFIG,
                                nil, nil, 0);
end;

procedure WinInetUnInit;
begin
  // closes the opened session.
  InternetCloseHandle(FInetSessionHandle);
end;

procedure WinInetGetDataFromURL(URL, User, Password : string; AStream : TMemoryStream);
const BufSize          = 1024;
      Terminator: Byte = $00;
var ReadResult         : Boolean;
    CanonicalizeURLSize,
    BytesRead          : DWord;
    FAddHeader         : string;
    Buffer             : array[0..(BufSize - 1)] of Char;
    FURL               : array[0..INTERNET_MAX_URL_LENGTH] of Char;
    FSessionContext    : DWord;
begin
  // init session context variable
  FSessionContext := 0;
  // if an authentication is required, an additional header entry is required.
  // for HTTP/HTTPS this header entry is e.g.
  // Authorization: Basic RERGERGEAGZTHTZ
  // where Username and password are Base64 encrypted
  if User <> ''
   then FAddHeader := 'Authorization: Basic ' + EncodeBase64(User + ':' + Password);

  // look if the session is open
  if FInetSessionHandle = nil
   then raise Exception.Create('Invalid session handle');

  // set maximum length of fully qualified URL
  CanonicalizeURLSize := INTERNET_MAX_URL_LENGTH + 1;
  // InternetCanonicalizeURL creates a fully qualified URL in the form
  // [protocol]://[server].([domain])(:[port])/([path])
  // Useful if you provide a relative URL (./dir/file.htm or /index.htm)
  if InternetCanonicalizeURL(PChar(URL), FURL, CanonicalizeURLSize, 0) = false
   then raise Exception.Create('InternetCanonicalizeURL Error code ' + IntToStr(GetLastError));

  // this function opens the URL.
  // it takes the current session, the URL, the additional header, the length of the additional header, a re-load and untyped data flag as parameters and stores the request handle in a context variable.
  // This context variable is used if you open multiple URLs at once, so not in this case.
  // The return value is a connection handle used for subsequent calls
  FConnectionHandle := InternetOpenURL(FInetSessionHandle, FURL, PChar(FAddHeader), Length(FAddHeader), INTERNET_FLAG_RELOAD or INTERNET_FLAG_RAW_DATA, FSessionContext);

  if FConnectionHandle = nil
   then raise Exception.Create('InternetOpenURL Error code ' + IntToStr(GetLastError));

  try
    // read data
    repeat
      // read data in chunks into a read buffer
      // This function takes the connection handle, the buffer adress and the buffer size as parameters, returns the bytes read in BytesRead.
      // The return value returns even true if the file is completely read, so we have to check the BytesRead parameter to check if the file is in.
      ReadResult := InternetReadFile(FConnectionHandle, @Buffer[0], BufSize, BytesRead);
      if ReadResult = false
       then Break;
      // you could also omit this line, in D3 the stream re-sizes dynamically.
      // if you use D2, you MUST delete this line, because D2 will destroy the stram content when resizing.
      AStream.SetSize(AStream.Size + BytesRead);
      // write the buffer content into the streams
      AStream.Write(Buffer[0], BytesRead);
    until BytesRead = 0;
    // same as abovce for D3 and D2
    AStream.SetSize(AStream.Size + 1);
    // terminate the stream with a zero char.
    // useful for text files wich can then br treat as strings.
    AStream.Write(Terminator, 1);
  finally
    // close the context opened by InternetOpenURL
    InternetCloseHandle(FConnectionHandle);
  end;
end;

end.

// sample: place a memo, a button and an edit field on a form. Include url_req in your uses-clause and add this code to the OnClick handler of the button:

procedure TForm1.Button1Click(Sender: TObject);
var AStream : TMemoryStream;
    TheURL  : string;
begin
  if Edit1.Text = ''
   then Exit;
  Memo1.Clear;
  AStream := TMemoryStream.Create;
  try
    TheURL := Edit1.Text;
    WinInetGetDataFromURL(TheURL, '', '', AStream);
    // here we use the string behaviour (mentioned above) of the stream
    Memo1.SetSelTextBuf(AStream.Memory);
  finally
    AStream.Free;
  end;
end;

If you have any further questions, just ask.

Slash/d003303
0
 
LVL 4

Expert Comment

by:d003303
ID: 1356826
sorry, the encoding lines

  if User <> ''
   then FAddHeader := 'Authorization: Basic ' + EncodeBase64 User + ':' + Password);

should read

  if User <> ''
   then FAddHeader := 'Authorization: Basic ' + EncodeStr(encBase64, User + ':' + Password);

Slash/d003303
0
 

Author Comment

by:fh1
ID: 1356827
To: d003303
How can I save the file instead of showing it on Memo?
And then, how do I know that download has been finished?
Thanks for your help.
0
 
LVL 4

Expert Comment

by:d003303
ID: 1356828
Yo,
the data is held in a memory stream. Just save it to disk. The download is finished when the WinInetGetDataFromURL procedure returns. I modified the demo code, add a SaveDialog component on the form.

procedure TForm1.Button1Click(Sender: TObject);
var AStream : TMemoryStream;
    TheURL,
    TheFile : string;
begin
  if Edit1.Text = ''
   then Exit;
// ok, no need for the memo
// Memo1.Clear;
  SaveDialog1.Title := 'Download selected file to';
  if not SaveDialog1.Execute
   then Exit;
  TheFile := SaveDialog1.FileName;
  AStream := TMemoryStream.Create;
  try
    TheURL := Edit1.Text;
    WinInetGetDataFromURL(TheURL, '', '', AStream);
// here we save the stream to a file
    AStream.SaveToFile(TheFile);
// this is a message that the download is complete
    Application.Messagebox('Download complete', 'Note', mb_ok);
// again, no need for the memo
//    Memo1.SetSelTextBuf(AStream.Memory);
  finally
    AStream.Free;
  end;
end;

Slash/d003303
0
 

Author Comment

by:fh1
ID: 1356829
To: d003303
I used your code and successfully downloded a text file.
Now I am trying to download a HTML file and show it on a delphi HTML component, but the file is corrupted(after downloading). What should I do to make the code work for an HTML file?

0

Featured Post

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
QRReport  TQrmemo vertical stretching 1 53
Convert a string into a TDateTime 5 64
Installshield for Embarcadero EX 10.1 Berlin 4 60
Delphi Seattle StructureView color 1 14
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…

829 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question