Borland 6, Indy 9.0.50 (upgraded from 8... probably a mistake)
TIdFTP FTP2;
TListBox RawDir;
Code looks roughly:
FTP2->Connect(true, 5000);
//if connected
FTP2->ChangeDir("AddOns");
FTP2->List(RawDir->Items, "*", true);
When I hit the list command I get the EidConnClosedGracefully exception.
If I try to step past it I just keep getting the error. If I ignore the
exceptions
(Tools->Debugger....) the program just hangs.
This was working great in version 8. Any ideas?
-Cory
> FTP2->List(RawDir->Items, "*", true);
>
> When I hit the list command I get the EidConnClosedGracefully exception.
As you should be. The FTP protocol uses a secondary connection for data
transfers and directory listings. You are simply seeing the exception that
is generated when the server closes that second connection. List() will
catch that exception internally. It will not reach your own code. Since
you are running your code inside the IDE debugger, the debugger will see all
exceptions. Simply press F9 to pass the exception back to the project for
normal handling. You should also add EIdSilentException (which
EIdConnClosedGracefully derives from) to your debugger's list of exceptions
to ignore.
Gambit
Ah Gambit, my favorite debugger. =)
So, adding EIdSilentException to my debugger list stops the
EIdConnClosedGracefully
exceptions. (What's F9? I've remapped my IDE)
But even after stopping the exceptions the FTP->List() command just hangs.
No
time out, no error, just hangs. Its odd. As per my last message, it worked
in
version 8, but not in 9. Any thoughts?
-Cory
> What's F9? I've remapped my IDE
It is the "Run" command.
> But even after stopping the exceptions the FTP->List() command just hangs.
Did you apply the TIdTCPConnection::ReadStream() fix that I have described
in other discussions? For example, have a look at the "Trouble with the
Last Indy9v with the CB6 vs. old Indy9" discussion from a few days ago in
this same newsgroup.
Gambit
Ah, very nice. Okay, I went in, applied the fix, recompiled the Indy
products
and re-ran my program.
No it no longer sticks on that point, but it just puts forth a dialog box
(with
red x icon) that says "Connection Closed Gracefully".
It also seems to stop any further progress into my function. I step to that
spot,
the dialog pops up (not an exception as I have them ignored) and even after
hitting okay on the dialog my IDE never comes back to my debug spot.
The program integrity seems to be okay (I can close it, move it, etc) but it
just wont continue?
-Cory
> No it no longer sticks on that point, but it just puts forth a dialog
> box (with red x icon) that says "Connection Closed Gracefully".
Are you still running inside the debugger at the time?
> It also seems to stop any further progress into my function. I step to
that
> spot,
> the dialog pops up (not an exception as I have them ignored) and even
after
> hitting okay on the dialog my IDE never comes back to my debug spot.
If you are inside the debugger, did you press the Run command after the
dialog was closed? When the debugger breaks on an exception, it will not
continue execution of the program until you explicitally tell it to do so.
Gambit
Still in the debugger, and even hitting 'Run' after closing the dialog box
(not an exception box, a program pop-up) does not cause it to continue.
-Cory
> Still in the debugger, and even hitting 'Run' after closing the dialog box
> (not an exception box, a program pop-up) does not cause it to continue.
There are no popup messages in Indy. "Connection Closed Gracefully" is an
exception message. If you are not seeing the debugger display an exception
popup for it, then your program has to be showing its own popup message,
such as in an exception handler. Or you are not catching any exceptions and
they are falling through to the VCL's default handler.
Please show your actual code. List() should not be throwing an "Connection
Closed Gracefully" exception, even with the ReadStream() fix applied.
Gambit
Below are the "basics". FTP2 is the TldFTP program. It calls the
parsedirectory
function and that's what fails. I've included the FormCreate function as
well
so you can see what's in it. The SaveLoad() just reads values from regestry
and puts them into a couple of edit boxes (unrelaed).
Stepping through the code I get to this line FTP2->List(RawDir->Items,"*",
true);
int the ParseDirectory function before it fails and throws the Dialog Box.
-Cory
//---------------------------------------------------------------------------
void __fastcall TForm1::ConnectClick(TObject *Sender)
{
int i;
TStringList *names;
if (!FTP2->Connected()) {
FTP2->Host = Server->Text;
FTP2->Username = UserName->Text;
FTP2->Password = AdminForm->Decode(Password->Text);
FTP2->Connect(true, 5000);
if (FTP2->Connected()) {
names = new TStringList ();
FTP2->ChangeDir("AddOns");
ParseDirectory (names, NULL, NULL, true);
RemoteDir->Items = names;
delete names;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ParseDirectory(TStringList *name, TStringList
*directory, TStringList *size, bool dironly)
{
int i;
bool dir;
AnsiString temp;
RawDir->Clear();
FTP2->List(RawDir->Items,"*", true);
for (i=0; i<RawDir->Count; i++) {
dir = false;
temp = RawDir->Items->Strings[i].SubString(0,10); //directory //0
based I think (Index , COunt)
if (temp.c_str()[0] == 'd' || temp.c_str()[0] == 'D') {
dir = true;
}
if (directory != NULL) {
if (dir || (!dironly)) {
directory->Add(temp);
}
}
temp = RawDir->Items->Strings[i].SubString(11,16); //Unknown
temp = RawDir->Items->Strings[i].SubString(27,16); //Size
if (size != NULL) {
if (dir || (!dironly)) {
size->Add(temp);
}
}
temp = RawDir->Items->Strings[i].SubString(44,12); //Date
temp = RawDir->Items->Strings[i].SubString(57,99); //Name
if (name != NULL) {
if (dir || (!dironly)) {
name->Add(temp);
}
}
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
AnsiString temp;
this->Left = 100;
this->Top = 100;
this->ClientWidth = 800;
this->ClientHeight = 600;
temp.printf("Interface Assistant v%d.%02d.%02d", MAJOR_VERSION,
MINOR_VERSION, VER_REV);
Form1->Caption = temp;
CurFile->Caption = "";
Size->Caption = "";
dt = NULL;
SaveLoad (ID_LOAD);
}
> I've included the FormCreate function as well so you can see what's in it.
DO NOT use the OnCreate event in C++! It is a Delphi idiom that produces
illegal behavior in C++ as it can be triggered before the constructor. Use
the actual constructor instead.
> Stepping through the code I get to this line FTP2->List(RawDir->Items,"*",
> true); int the ParseDirectory function before it fails and throws the
Dialog Box.
Did you try putting try..catch blocks into your code yet?
__fastcall TForm1::TForm1(TComponent *Owner)
: TForm(Owner)
{
this->Left = 100;
this->Top = 100;
this->ClientWidth = 800;
this->ClientHeight = 600;
AnsiString temp;
temp.printf("Interface Assistant v%d.%02d.%02d", MAJOR_VERSION,
MINOR_VERSION, VER_REV);
this->Caption = temp;
CurFile->Caption = "";
Size->Caption = "";
dt = NULL;
SaveLoad (ID_LOAD);
}
void __fastcall TForm1::ConnectClick(TObject *Sender)
{
if( !FTP2->Connected() )
{
FTP2->Host = Server->Text;
FTP2->Username = UserName->Text;
FTP2->Password = AdminForm->Decode(Password->Text);
try
{
FTP2->Connect(true, 5000);
try
{
FTP2->ChangeDir("AddOns");
if( !ParseDirectory(RemoteDir->Items, NULL, NULL,
true) )
ShowMessage("Parse Directory Error");
}
catch(const Exception &)
{
FTP2->Disconnect();
throw;
}
}
catch(const Exception &e)
{
ShowMessage(e.Message);
}
}
}
bool __fastcall TForm1::ParseDirectory(TStrings *name, TStrings
*directory, TStrings *size, bool dironly)
{
bool dir;
AnsiString item, temp;
RawDir->Clear();
try
{
FTP2->List(RawDir->Items,"*", true);
}
catch(const Exception &)
{
return false;
}
for(int i = 0; i < RawDir->Count; ++i)
{
dir = false;
item = RawDir->Items->Strings[i];
temp = item.SubString(1, 10); //directory
if( (temp != "") && ((temp[1] == 'd') || (temp[1] == 'D')) )
dir = true;
if( (directory) && ((dir) || (!dironly)) )
directory->Add(temp);
temp = item.SubString(11, 16); //Unknown
temp = item.SubString(27, 16); //Size
if( (size) && ((dir) || (!dironly)) )
size->Add(temp);
temp = item.SubString(44, 12); //Date
temp = item.SubString(57, 99); //Name
if( (name) && ((dir) || (!dironly)) )
name->Add(temp);
}
return true;
}
Gambit
Okay, put in the try/catch block where located, and the FTP2->List command
catchs an exception and my function ends.
No idea what to do next, doesn't do me any good if List just fails.
Move all items out of the "OnCreate" event into the constructor
-Cory
ps. Is there any way to go from Indy 9 to 8 easily?
> Okay, put in the try/catch block where located, and the FTP2->List
> command catchs an exception and my function ends.
EIdConnClosedGracefully is only thrown when a socket is directly accessed
after it has been closed by the other party, and even then only after the
TIdTCPConnection.InputBuffer property has been emptied or otherwise cannot
satisfy anymore read operations.
Remember that file transfers and directory listings use a second socket
connection. After applying the fix for ReadSteam() (which List() calls on
the second connection to download the listing data), the only remaining way
for List() to throw EIdConnClosedGracefully is if the main command
connection is being closed by the server, since ReadStream() will catch and
discard the EIdConnClosedGracefully on the second data connection in this
situation.
> Is there any way to go from Indy 9 to 8 easily?
No.
Gambit