Link to home
Start Free TrialLog in
Avatar of goaman
goaman

asked on

Please can anyone Fix this code... (Downloading a file from the Net)

Hi There!
I need help.. pls help me out to solve this problem... I want a "TProgressbar to indicates the download, TLabel gets the time left to finish the download file and the current downloading speed in KB/s?"...


[code]

function DownloadMyFile(SourceFile, DestFile: string): Boolean;
begin
Form1.ProgressBar1.Position:=0;
Form1.ProgressBar1.Max:=
  try
    Result :=  UrlDownloadToFile(nil, PChar(SourceFile), PChar(DestFile), 0, nil) = 0;
Form1.ProgressBar1.Position:=
Form1.kbps.Caption:=
Form1.TimeLeft.Caption:=

  except
    Result := False;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 if DownloadFile(edit1.text ,edit2.text) then
begin
MessageDlg('Download Successful!',mtInformation, [mbOK], 0);
 ShellExecute(Application.Handle, PChar('open'), PChar(Edit2.Text), PChar(''), nil, SW_NORMAL);
end
  else
MessageDlg('Error downloading the file!', mtError, [mbOK], 0)
end;

end.
[/code]


Please complete this unfinished code.. Thanks in advance!
Avatar of Darth_helge
Darth_helge

this is exactly what you need - IBindStatusCallBack

you can look how to do it from here:
https://www.experts-exchange.com/questions/20349921/UrlDownloadToFile-IBindStatusCallback.html
isn't it easier to use the Indy Component IdHttp? less code writing?
Avatar of goaman

ASKER

Hi  Darth_helge,
The link is Not Found on the server...
The requested URL /Programming/Programming_Languages/Delphi/Q_20887936.htm was not found on this server.


Hi Ivanov_G,
This article seems a little mess, no progressbar, no speed showing or anything.. only form1 caption shows the downloading bytes.. pls Help me... Could you pls fix the code that I've posted up there... the way I wanted... or is there any better example which shows progressbar, time left and kb/s while downloading?

If anyone need I can increase the points... just let me know...pls, I really need this...

Thanx in advance!
I forgot the last letter....

I think that by doing this way it's a lot more easier.

https://www.experts-exchange.com/questions/20887936/show-that-program-is-downloading-using-progressbar.html
Avatar of goaman

ASKER

Darth_helge,
I saw that code b4... and yes it's easy way but I wanna know how to do without IdHTTP component + This example doesn't have everything I need.. :(
the question I gave you doesn't use TidHTTP...
Avatar of goaman

ASKER

Ivanov_G  yes, it doesn't use IdHTTP component...  but the example is not advanced... could you please edit that example and place there progressbar to show the downloading and the problem is I don't know how to show Downloading Speed and Tlabel which shows the time how long will it take to download the file.. could you give me a hand in this?
<<I saw that code b4... and yes it's easy way but I wanna know how to do without IdHTTP component + This example doesn't have everything I need.. :(
   ok, I can't see why you don't wanna use that component, but in that case, Ivanov_G has a great answer for you.

Maybe you can fill me in Ivanov? Why is the interface you are suggesting better than TIdHTTP?
Darth_helge, did I said it is better ?! If so, pleaso quote my word where I claim this...
Ivanov, I was not intending to be rude. By all means, I respect your answer, and I am sure that you are a much better programmer than me.
I was simply curious about your solution, and what is good about it.

As I could see from mine and your solutions, I saw that mine was less complex and did the same thing (I think...).
But maybe e.g your solution i faster or more secure or more flexible...   ..I don't know. That was the thing I asked you about.

Sorry if I made you upset

I just gave a suggestion, the author if the one who choose the solution. I also think you solution is more simple and easier to implement.
Avatar of Eddie Shipman
Try this modification of using IBindStatusCallBack to see how it works. Also, you are going
to need to get the file size BEFORE downloading so you can set the Progressbar's Max property.


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, UrlMon, ComCtrls, StdCtrls, ActiveX;

type
  TBindStatusCallback = class(TObject, IBindStatusCallback)
  protected
     FRefCount: Integer;
     // IUnknown
     function QueryInterface(const IID: TGUID; out Obj): Integer; stdcall;
     function _AddRef: Integer; stdcall;
     function _Release: Integer; stdcall;
  public
     // IBindStatusCallback
    function OnStartBinding(dwReserved: DWORD; pib: IBinding): HResult; stdcall;
    function GetPriority(out nPriority): HResult; stdcall;
    function OnLowResource(reserved: DWORD): HResult; stdcall;
    function OnProgress(ulProgress, ulProgressMax, ulStatusCode: ULONG;
                        szStatusText: LPCWSTR): HResult; stdcall;
    function OnStopBinding(hresult: HResult; szError: LPCWSTR):
             HResult; stdcall;
    function GetBindInfo(out grfBINDF: DWORD; var bindinfo: TBindInfo):
             HResult; stdcall;
    function OnDataAvailable(grfBSCF: DWORD; dwSize: DWORD; formatetc: PFormatEtc;
                             stgmed: PStgMedium): HResult; stdcall;
    function OnObjectAvailable(const iid: TGUID; punk: IUnknown): HResult; stdcall;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    ProgressBar1: TProgressBar;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  bsc: TBindStatusCallback;


implementation

{$R *.dfm}


function GetEstimatedCompletion(ATtlFileSize, ACompletedBytes: Integer; ABgTime: TDateTime): String;
var
  LeftTime: TDateTime;
begin
  Result     := '';
  LeftTime   := (Now - ABgTime) / ACompletedBytes* (ATtlFileSize- ACompletedBytes);
  Result     := FormatDateTime('hh:nn:ss', LeftTime);
end;

function TBindStatusCallback.QueryInterface(const IID: TGUID;
  out Obj): Integer;
begin
  if GetInterface(IID, Obj) then Result := S_OK
                            else Result := E_NOINTERFACE; end;

function TBindStatusCallback._AddRef: Integer;
begin
 Inc(FRefCount);
 Result := FRefCount;
end;

function TBindStatusCallback._Release: Integer;
begin
 Dec(FRefCount);
 Result := FRefCount;
end;

function TBindStatusCallback.GetBindInfo(out grfBINDF: DWORD;
  var bindinfo: TBindInfo): HResult;
begin
  Result := E_NOTIMPL;
end;

function TBindStatusCallback.GetPriority(out nPriority): HResult;
begin
  Result := E_NOTIMPL;
end;

function TBindStatusCallback.OnDataAvailable(grfBSCF, dwSize: DWORD;
  formatetc: PFormatEtc; stgmed: PStgMedium): HResult;
begin
  Result := E_NOTIMPL;
end;

function TBindStatusCallback.OnLowResource(reserved: DWORD): HResult;
begin
  Result := E_NOTIMPL;
end;

function TBindStatusCallback.OnObjectAvailable(const iid: TGUID;
  punk: IUnknown): HResult;
begin
  Result := E_NOTIMPL;
end;

function TBindStatusCallback.OnStartBinding(dwReserved: DWORD;
  pib: IBinding): HResult;
begin
  Result := E_NOTIMPL;
end;

function TBindStatusCallback.OnStopBinding(hresult: HResult;
  szError: LPCWSTR): HResult;
begin
  Result := E_NOTIMPL;
end;

function TBindStatusCallback.OnProgress(ulProgress, ulProgressMax,
  ulStatusCode: ULONG; szStatusText: LPCWSTR): HResult;
begin
  // Do something, for example, show progress:
  Form1.Caption:='Downloaded: '+IntToStr(ulProgress) +' bytes';
  Form1.ProgressBar1.Position :=  ulProgress;
  // To PREVENT Divide By Zero Errors!!
  if ulProgress > 0 then
  begin
    Form1.StatusBar1.Panels[0].Text := 'Estimated Completion time: ' +
           GetEstimatedCompletion(giFileSize, ulProgress, gdtBegtime);
  end;
  Result := S_OK;
  // Place some abort flag here. For demo purpose here, cancel when
  // CancelButton.Tag is set to 1:
  if Form1.CancelButton.Tag = 1 then
  begin
     Result := E_ABORT;
     Form1.Caption:='Download aborted!'
     // Reset the CancelButton's tag
     Form1.CancelButton.Tag := 0;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  // you need to get the file size and set the Progressbar's Max property
  // here.
  case
  URLDownloadToFile(nil,
                    'https://www.experts-exchange.com/questions/21087833/Please-can-anyone-Fix-this-code-Downloading-a-file-from-the-Net.html,
                    'c:\ee-question.html', 0 , bsc);
end;

procedure TForm1.CancelButtonClick(Sender: TObject);
begin
  case TButton(Sender).Tag of
    0: TButton(Sender).Tag := 1;
    1: TButton(Sender.Tag := 0; // should never go here because it is reset in OnProgress.
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  bsc:=TBindStatusCallback.Create;
end;

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

end.
Avatar of goaman

ASKER

hi EddieShipman,
I'm getting List index out of bounds(0)..
You must have more than one panel in your statusbar. I think that is where it is coming from.
You can also change this line:
 Form1.StatusBar1.Panels[0].Text := 'Estimated Completion time: ' +
           GetEstimatedCompletion(giFileSize, ulProgress, gdtBegtime);

to this if SimpleText is True:

 Form1.StatusBar1.SimpleText := 'Estimated Completion time: ' +
           GetEstimatedCompletion(giFileSize, ulProgress, gdtBegtime);
Avatar of goaman

ASKER

It's working only when I set it to form1.caption:= 'Estimated Completion time: ' +
           GetEstimatedCompletion(giFileSize, ulProgress, gdtBegtime);

because form1 freezing while downloading except the form1.caption and progressbar




I think there is something wron with this function:

function GetEstimatedCompletion(ATtlFileSize, ACompletedBytes: Integer; ABgTime: TDateTime): String;
var
  LeftTime: TDateTime;
begin
  Result     := '';
  LeftTime   := (Now - ABgTime) / ACompletedBytes* (ATtlFileSize- ACompletedBytes);
  Result     := FormatDateTime('hh:nn:ss', LeftTime);
end;


because it's showing the system's current time..
ASKER CERTIFIED SOLUTION
Avatar of Eddie Shipman
Eddie Shipman
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ok, I see what is wrong, now. We are not setting the gdtBegTime and giFileSize.
You need to do that when the GoButton is clicked.

procedure TForm1.GoButtonClick(Sender: TObject);
begin
  // you need to get the file size and set the Progressbar's Max property
  // here.
  gdtBegtime := Now;
  giFileSize := 76738; // Get the file size and set here, this is value only for demo purposes.
  ProgressBar1.Max:=giFileSize;
  URLDownloadToFile(nil,
                    'https://www.experts-exchange.com/questions/21087833/Please-can-anyone-Fix-this-code-Downloading-a-file-from-the-Net.html,
                    'c:\ee-question.html', 0 , bsc);
end;
I have modified this to get the filesize using idHTTP.Head, however, this site sometimes does not return
complete headers, I don't know why. It doesn't send Content-Length all the time like the RFC specifies that
it should, but of course, EE isn't very good at following standards, especially Web UI standards. You will
have to test with your URLs.

If you don't want to use TidHTTP to get the file size, you will have to use other WinInet means.


procedure TForm1.GoButtonClick(Sender: TObject);
var
  sURL: String;
  sFileSize: String;
begin
  sURL := 'https://www.experts-exchange.com/questions/21087833/Please-can-anyone-Fix-this-code-Downloading-a-file-from-the-Net.html;
  // you need to get the file size and set the Progressbar's Max property
  // here.
  idHTTP1.Head(sURL);
  idHTTP1.Head(sURL);
  sFileSize := idHTTP1.Response.RawHeaders.Values['Content-Length'];
  if sFileSize <> '' then
    giFileSize := StrToInt(sFileSize)
  else
    giFileSize := 0;
  gdtBegtime := Now;
  ProgressBar1.Max:=giFileSize;
  URLDownloadToFile(nil, PChar(sURL), 'c:\ee-question.html', 0 , bsc);
end;