Mahesh Yadav
asked on
Idftp.Get hangs my application.. how to trap the error if connection is lost
I am using Delphi 6 and Indy component 10. In my application i need to download some files from the ftp server. I am using IdFtp.Get method. Below is my code sample: -
Function TFormMain.DownloadFile(str URL: String; strLocalPath: string): Boolean;
Begin
Result := False;
try
try
IdFTP1.Connect;
IdFTP1.Get(strURL, strLocalPath, True);
Result := True;
except
on E: Exception do begin
MessageDlg(e.Message ,mtError, [mbOK], 0);
Exit;
end
end;
finally
IdFTP1.Disconnect;
end;
end;
Now if after idFTP.Get command is excuted and internet connection gets lost, my application simple hangs. ReadTimeout property & try..except does not seems to be helpful in this senario.
I want to trap this error so that i can reconnect to internet and resume downloading my file.
If anyone can provide sample code that will really be helpful.
Thanks
Function TFormMain.DownloadFile(str
Begin
Result := False;
try
try
IdFTP1.Connect;
IdFTP1.Get(strURL, strLocalPath, True);
Result := True;
except
on E: Exception do begin
MessageDlg(e.Message ,mtError, [mbOK], 0);
Exit;
end
end;
finally
IdFTP1.Disconnect;
end;
end;
Now if after idFTP.Get command is excuted and internet connection gets lost, my application simple hangs. ReadTimeout property & try..except does not seems to be helpful in this senario.
I want to trap this error so that i can reconnect to internet and resume downloading my file.
If anyone can provide sample code that will really be helpful.
Thanks
if ftpserver support resuming, try to have an idea of that code;
var
F: TFileStream;
localsize:integer;
netsize:integer;
begin
localsize:=0;
netsize:=0;
repeat
try
IdFTP1.Connect;
if localsize>0 then IdFTP1.Position := localsize;
IdFTP1.Get(strURL, strLocalPath, True);
netsize:=IdFTP1.Size;
except
IdFTP1.Disconnect;
F := TFileStream.Create(strLocalPath, fmOpenRead or fmShareDenyNone);
localsize:=F.Size;
end;
until localsize=netsize;// or terminated;
end;
Do your uploads and downloads in a thread and your application will be responsive. Check the TidStatus and monitor the progress. If you get an error status or there is no response for a defined period of time, clear the channel, and reset the connection.
ASKER
Thanks for your response.
But my problem is if internet connection is lost IdFtp.Get simply hangs my application, it is not coming in exception block. How to catch that error? If i can catch that error then only i can implement what you have suggested about resume downloading.
But my problem is if internet connection is lost IdFtp.Get simply hangs my application, it is not coming in exception block. How to catch that error? If i can catch that error then only i can implement what you have suggested about resume downloading.
>>internet connection is lost?
if you unplug the cable? wired/wireless,
Ohm, better try it not on delphi environment, run it as an exe file.
if you unplug the cable? wired/wireless,
Ohm, better try it not on delphi environment, run it as an exe file.
ASKER
Yes if say i unplug the cable...and internet is not connected after firing the idFtp.Get command
i am running it as a exe file....
i am running it as a exe file....
ASKER
ewangoya:
I did try using Thread but it did not solve my problem... may be i did something wrong...
Is it possible for you to create a sample code for me....
Thanks
I did try using Thread but it did not solve my problem... may be i did something wrong...
Is it possible for you to create a sample code for me....
Thanks
is your ftpserver supports resuming?
ASKER
Not sure, how can i check that?
But even if ftpserver does not support resuming, i still need to either close the application or display some message instead of application getting hanged when internet connection is lost after idFtp.Get.
But even if ftpserver does not support resuming, i still need to either close the application or display some message instead of application getting hanged when internet connection is lost after idFtp.Get.
Put a Disconnect at the first line of the except section.
try
IdFTP1.Connect;
/////IdFTP1.Get(STIRNGstrU RL, STREAMstrLocalPath, ResumeTrue);
IdFTP1.Get(STIRNGstrURL, STRINGstrLocalPath, overwriteFALSE, ResumeTRUE);
except
IdFTP1.Disconnect;
///some code here to connect it again if error occurs
end;
try
IdFTP1.Connect;
/////IdFTP1.Get(STIRNGstrU
IdFTP1.Get(STIRNGstrURL, STRINGstrLocalPath, overwriteFALSE, ResumeTRUE);
except
IdFTP1.Disconnect;
///some code here to connect it again if error occurs
end;
ASKER
But problem is if after idFtp1.Get i disconnect my internet connection... then cursor is not coming to except block... application simply hangs that the issue...
@ziorinfo
I'll create sample code with threading in the weekend if no solution will have been provided by then.
I'll create sample code with threading in the weekend if no solution will have been provided by then.
ASKER
ewangoya:
Thanks. So fat still waiting for the solution :(
Thanks. So fat still waiting for the solution :(
what version of delphi your using?
ASKER
Delphi 6 & Indy 10
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks ewangoya: for the sample code.
But i am not able implement it properly.. My application runs at seperately in the tray icon.. its job is toh download setup file and after downloading run the setup file.
Now if i implement your thead code, how do i make my application wait untill i hear something from the thread...
But i am not able implement it properly.. My application runs at seperately in the tray icon.. its job is toh download setup file and after downloading run the setup file.
Now if i implement your thead code, how do i make my application wait untill i hear something from the thread...
In the example, there is a procedure called DoTerminate; which tells you when the thread is done running
Currently it just has a message showmessage('done');
Replace the showmessage with your code to run the setup. Preferebly, use SendMessage to invoke processing of your next action
eg
const
UM_DOWNLOAD_COMPLETED = WM_USER + 101;
procedure TForm2.Doterminate;
begin
SendMessage(Handle, UM_DOWNLOAD_COMPLETED, 0, 0);
end;
add method to the form
procedure TForm2.UMDOWNLOADCOMPLETED (var Message: TMessage); message UM_DOWNLOAD_COMPLETED;
implement
procedure TForm2.UMDOWNLOADCOMPLETED (var Message: TMessage);
begin
//do something with the download, run your setup
end;
Currently it just has a message showmessage('done');
Replace the showmessage with your code to run the setup. Preferebly, use SendMessage to invoke processing of your next action
eg
const
UM_DOWNLOAD_COMPLETED = WM_USER + 101;
procedure TForm2.Doterminate;
begin
SendMessage(Handle, UM_DOWNLOAD_COMPLETED, 0, 0);
end;
add method to the form
procedure TForm2.UMDOWNLOADCOMPLETED
implement
procedure TForm2.UMDOWNLOADCOMPLETED
begin
//do something with the download, run your setup
end;
ASKER
ewangoya:
This is what i am doing: -
I am launching my Download application from my main application. My download application does not apper on the task bar, i am showing it in the tray icon using TCoolTrayIcon. The purpose of this applicaton is to download the file from the server and run it.
Now if i implement your thread example to download the file...
After creating the thread.. excution of my applicaiton continues and it gets terminated as there is nothing else to do....instead my application should wait untill file is downloaded or else an error should be generated if internet connection was lost while downloading the file..
Function TFormMain.DownloadFile(str URL: String; strLocalPath: string): Boolean;
var
DownloadThread : TTransferThread;
Begin
Result := False;
try
try
strURL := StringReplace(strURL, 'ftp.yousway.ch', '',[rfReplaceAll, rfIgnoreCase]);
ThreadTerminated := False;
DownloadThread := TTransferThread.Create(IdF TP1.Host, IdFTP1.Username, IdFTP1.Password, strURL, strLocalPath, ftpaDownload );
{I want to return true once the download is completed or show an error message if download could not be completed or if net connection is lost}
Result := True;
end;
This is what i am doing: -
I am launching my Download application from my main application. My download application does not apper on the task bar, i am showing it in the tray icon using TCoolTrayIcon. The purpose of this applicaton is to download the file from the server and run it.
Now if i implement your thread example to download the file...
After creating the thread.. excution of my applicaiton continues and it gets terminated as there is nothing else to do....instead my application should wait untill file is downloaded or else an error should be generated if internet connection was lost while downloading the file..
Function TFormMain.DownloadFile(str
var
DownloadThread : TTransferThread;
Begin
Result := False;
try
try
strURL := StringReplace(strURL, 'ftp.yousway.ch', '',[rfReplaceAll, rfIgnoreCase]);
ThreadTerminated := False;
DownloadThread := TTransferThread.Create(IdF
{I want to return true once the download is completed or show an error message if download could not be completed or if net connection is lost}
Result := True;
end;
You need a variable in your form that will store the result of the download and another to signal that the thread is still running. This variable will then be set in the DoTerminate procedure.
On the form
private
FDownloadSuccessful: Boolean;
FThreadRunning: Boolean;
procedure TForm2.DoTerminate;
begin
FDownloadSuccessful := (Sender as TTransferThread).DownloadS uccessful;
SendMessage(Handle, UM_DOWNLOAD_COMPLETED, 0, 0);
end;
procedure TForm2.UMDOWNLOADCOMPLETED (var Message: TMessage);
begin
FThreadRunning := False;
if FDownloadSuccessful then
begin
//run the set
//After you are done witht the process, thaen only can you close application
end;
//close application
PostMessage(Handle, WM_CLOSE, 0, 0);
end;
//set thread running and do not close your application while it is running
procedure TFormMain.DownloadFile(str URL: String; strLocalPath: string);
var
DownloadThread : TTransferThread;
Begin
try
try
strURL := StringReplace(strURL, 'ftp.yousway.ch', '',[rfReplaceAll, rfIgnoreCase]);
FThreadRunning := True;
DownloadThread := TTransferThread.Create(IdF TP1.Host, IdFTP1.Username, IdFTP1.Password, strURL, strLocalPath, ftpaDownload );
DownloadThread.OnTerminate := DoTerminate; //this will signal the thred has ended
.............
in the thread also add
TTransferThread = class(TThread)
private
FDownloadSuccessful: Boolean;
.....
property
property DownloadSuccessful: Boolean read FDownloadSuccessful;
....
end;
Anytime you get an exception, set FDownloadSuccessful := False
case FFTPAction of
ftpaDownload:
begin
try
FFTP.Get(FSourceFile, FDestinationFile, True);
FDownloadSuccessful := True;
except
on E: EIdReadTimeout do
begin
FDownloadSuccessful := False;
//connection is broken or other time out
//Handle exception
end;
on E: Exception do
begin
FDownloadSuccessful := False;
//all other exceptions
end;
end;
end;
On the form
private
FDownloadSuccessful: Boolean;
FThreadRunning: Boolean;
procedure TForm2.DoTerminate;
begin
FDownloadSuccessful := (Sender as TTransferThread).DownloadS
SendMessage(Handle, UM_DOWNLOAD_COMPLETED, 0, 0);
end;
procedure TForm2.UMDOWNLOADCOMPLETED
begin
FThreadRunning := False;
if FDownloadSuccessful then
begin
//run the set
//After you are done witht the process, thaen only can you close application
end;
//close application
PostMessage(Handle, WM_CLOSE, 0, 0);
end;
//set thread running and do not close your application while it is running
procedure TFormMain.DownloadFile(str
var
DownloadThread : TTransferThread;
Begin
try
try
strURL := StringReplace(strURL, 'ftp.yousway.ch', '',[rfReplaceAll, rfIgnoreCase]);
FThreadRunning := True;
DownloadThread := TTransferThread.Create(IdF
DownloadThread.OnTerminate
.............
in the thread also add
TTransferThread = class(TThread)
private
FDownloadSuccessful: Boolean;
.....
property
property DownloadSuccessful: Boolean read FDownloadSuccessful;
....
end;
Anytime you get an exception, set FDownloadSuccessful := False
case FFTPAction of
ftpaDownload:
begin
try
FFTP.Get(FSourceFile, FDestinationFile, True);
FDownloadSuccessful := True;
except
on E: EIdReadTimeout do
begin
FDownloadSuccessful := False;
//connection is broken or other time out
//Handle exception
end;
on E: Exception do
begin
FDownloadSuccessful := False;
//all other exceptions
end;
end;
end;
ASKER
ewangoya:
thanks for the the sample code. but i am still having problem....
in the time thread u have written
if (SecondsBetween(Now, FLastUpdateTime) > FMaxIdleTime) then
begin
FMonitorThread.Canceled := True;
IsRunning := False;
end;
FLastUpdateTime is always 0 not getting set and through this condition is false it still comes inside the if statement n thread is terminated.
any idea?
thanks for the the sample code. but i am still having problem....
in the time thread u have written
if (SecondsBetween(Now, FLastUpdateTime) > FMaxIdleTime) then
begin
FMonitorThread.Canceled := True;
IsRunning := False;
end;
FLastUpdateTime is always 0 not getting set and through this condition is false it still comes inside the if statement n thread is terminated.
any idea?
We need to initalize FLastUpdatetime to current time immediately before we start the thread
FLastUpdatetime := Now;
DownloadThread := TTransferThread.Create(IdF TP1.Host, IdFTP1.Username, IdFTP1.Password, strURL, strLocalPath, ftpaDownload );
FLastUpdatetime := Now;
DownloadThread := TTransferThread.Create(IdF
ASKER
Yes i am doing it but in the Timer thread it is still 0 and thread is getting cancelled.
You did not pass the DoWork procedure to the thread, that is what updates the LastUpdateTime to show the thread is running
I have attached an updated version for your reference
For the timer thread, also pass in the DoLastUpdateGetTime procedure
ftpUnit.pas
Unit2.pas
Unit2.dfm
I have attached an updated version for your reference
For the timer thread, also pass in the DoLastUpdateGetTime procedure
ftpUnit.pas
Unit2.pas
Unit2.dfm
you can resume it if the ftp server supports it.