Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Downloding a file with Internet Explorer

Posted on 1998-07-01
10
Medium Priority
?
642 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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 800 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

Ask an Anonymous Question!

Don't feel intimidated by what you don't know. Ask your question anonymously. It's easy! Learn more and upgrade.

Question has a verified solution.

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

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
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…
Want to learn how to record your desktop screen without having to use an outside camera. Click on this video and learn how to use the cool google extension called "Screencastify"! Step 1: Open a new google tab Step 2: Go to the left hand upper corn…
Are you ready to place your question in front of subject-matter experts for more timely responses? With the release of Priority Question, Premium Members, Team Accounts and Qualified Experts can now identify the emergent level of their issue, signal…

782 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