Solved

Downloding a file with Internet Explorer

Posted on 1998-07-01
10
611 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
PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

 
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

Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Delphi XE2 application frozen on Windows 10 10 311
how to center only a line in richedit? 4 57
How to define IfThen functions in one common unit? 4 54
Base1 Encode/Decode 3 77
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
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…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

773 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