Solved

Downloding a file with Internet Explorer

Posted on 1998-07-01
10
597 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
Comment Utility
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
Comment Utility
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
Comment Utility
Please add comments to your code so I can understand it.
0
 
LVL 7

Expert Comment

by:jconde
Comment Utility
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
Comment Utility
Sure, I add comments. Please re-open the question first.

Slash/d003303
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 4

Accepted Solution

by:
d003303 earned 200 total points
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

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…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

772 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now