Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Hair 0, Indy10 1

48 views
Skip to first unread message

Gene Buckle

unread,
May 30, 2008, 5:10:25 PM5/30/08
to
I'm trying to use TIdTCPClient directly and not in association with any form.
I'm using (or trying to) it within another class.

My class constructor goes something like this:

void __fastcall classSimulator::InitCommSystem() {
busy = true;
TCPClient = new TIdTCPClient(this);
IOHandler = new TIdIOHandlerStream(NULL);
TCPClient->IOHandler = IOHandler;
TCPClient->OnDisconnected = MainForm->DisconnectHandler;
busy = false;
}

Now the line:
TCPClient = new TIdTCPClient(this);
Dies during compile because "Could not find a match for TIdTCPClient::
TIdTCPClient(classSimulator* const)", which is perfectly reasonable.
That's why I'd changed it from "this" to NULL like the IOHandler below it.

Now while calling it with (NULL) compiles, it doesn't actually appear to work.

When I do this:
TCPClient->Host = "localhost";
TCPClient->Port = 5500;

and then

ShowMessage(TCPClient->Host);

The dialog shows nothing.

I can call TCPClient->Connect() and get no exception, yet
TCPClient->Connected() returns false.

Calling TCPClient->IOHandler->Connected() (or anything else under
TCPClient->IOHandler) just pitches an access violation exception.

What do I need to do in order to make this thing work?

thanks all

g.

--
Proud owner of F-15C 80-0007
http://www.f15sim.com - The only one of its kind.

Remy Lebeau (TeamB)

unread,
May 30, 2008, 6:18:00 PM5/30/08
to

"Gene Buckle" <ge...@grumble.deltasoft.com> wrote in message
news:4840...@newsgroups.borland.com...

> Now the line:
> TCPClient = new TIdTCPClient(this);
> Dies during compile because "Could not find a match for TIdTCPClient::
> TIdTCPClient(classSimulator* const)", which is perfectly reasonable.

Yes, since your classSimulator class is not a TComponent descendant.

> That's why I'd changed it from "this" to NULL like the IOHandler
> below it.

That is perfectly fine to do.

> Now while calling it with (NULL) compiles, it doesn't actually appear to
> work.

Yes, it does.

> When I do this:
> TCPClient->Host = "localhost";
> TCPClient->Port = 5500;
>
> and then
>
> ShowMessage(TCPClient->Host);
>
> The dialog shows nothing.

It should. TIdTCPClient does not do anything to reset that property back to
an empty string.

> I can call TCPClient->Connect() and get no exception,
> yet TCPClient->Connected() returns false.

You are using TIdIOHandlerStream, but you did not assign any TStream objects
to its ReceiveStream and SendStream properties.

If you are trying to establish an actual TCP/IP connection, then you need to
use TIdIOHandlerStack instead. Or just leave the IOHandler set to NULL.
Connect() will create its own TIdIOHandlerStack internally if you do not
have your own IOHandler assigned.

> Calling TCPClient->IOHandler->Connected() (or anything else under
> TCPClient->IOHandler) just pitches an access violation exception.

It will only do that if the IOHandler is NULL, which is not the case in your
code you have shown.


Gambit


Gene Buckle

unread,
May 30, 2008, 6:52:37 PM5/30/08
to
"Remy Lebeau \(TeamB\)" <no....@no.spam.com> wrote:
>
>> Now while calling it with (NULL) compiles, it doesn't actually appear to
>> work.
>
> Yes, it does.
>
Whatever it does, does not contribute to the proper function of the component. :)

>> When I do this:
>> TCPClient->Host = "localhost";
>> TCPClient->Port = 5500;
>>
>> and then
>>
>> ShowMessage(TCPClient->Host);
>>
>> The dialog shows nothing.
>
> It should. TIdTCPClient does not do anything to reset that property back to
> an empty string.
>

That's what it does. ShowMessage(TCPClient->Host) creates a blank dialog box.



>> I can call TCPClient->Connect() and get no exception,
>> yet TCPClient->Connected() returns false.
>
> You are using TIdIOHandlerStream, but you did not assign any TStream objects
> to its ReceiveStream and SendStream properties.
>

It would help if that kind of thing were documented.. Oh wait.
I keep forgetting who this is from. :)



> If you are trying to establish an actual TCP/IP connection, then you need to
> use TIdIOHandlerStack instead. Or just leave the IOHandler set to NULL.
> Connect() will create its own TIdIOHandlerStack internally if you do not
> have your own IOHandler assigned.
>

Ok, great. Dropped the specific assignment of the IOHandler.



>> Calling TCPClient->IOHandler->Connected() (or anything else under
>> TCPClient->IOHandler) just pitches an access violation exception.
>
> It will only do that if the IOHandler is NULL, which is not the case in your
> code you have shown.

Well it apparently can't read your reply because it continues to do it in the
face of your opposition. :) After leaving IOHandler unassigned, it
continues to throw exceptions:
Simulator->TCPClient->IOHandler->WriteLn("foo!");
...results in an access violation.


Any suggestions as to how I can actualy make this work? A C++ example would
be great.

I figure I'm either doing something really simple, really wrong, or their
software is terminally broken. Either way I need it to work as advertised
or I need a pointer to a similar component that will actually WORK with CB2k7.

thanks.

Remy Lebeau (TeamB)

unread,
May 30, 2008, 8:21:41 PM5/30/08
to

"Remy Lebeau (TeamB)" <no....@no.spam.com> wrote in message
news:4840999e$1...@newsgroups.borland.com...

> Have you actually looked at Indy's documentation yet?
>
> http://www.indyproject.org/Sockets/Docs/index.EN.aspx

Specifically:

http://www.indyproject.org/docsite/html/TIdIOHandlerStream_Connected.html

Connected is an overidden Boolean function used to indicate that
connection for the IOHandler has been established, and that a stream (or
streams) have been assigned for the IOHandler.

The return value for the function is True when valid stream instances
are assigned for the IOHandler.

Connected uses StreamType to determine the streams be checked for valid
stream instances in the IOHandler. Connected returns True when the following
conditions are met for the indicated StreamType:

stRead ReceiveStream is assigned.
stWrite SendStream is assigned.
stReadWrite Both ReceiveStream and SendStream are assigned.


Gambit


Remy Lebeau (TeamB)

unread,
May 30, 2008, 8:18:54 PM5/30/08
to

"Gene Buckle" <ge...@grumble.deltasoft.com> wrote in message
news:4840...@newsgroups.borland.com...

> Whatever it does, does not contribute to the proper function of the
> component. :)

Passing NULL versus 'this' to the constructor has no effect whatsoever on
TIdTCPClient's ability to function. All it does is establishes who is
responsible for freeing the memory of the TIdTCPClient instance, nothing
more.

> ShowMessage(TCPClient->Host) creates a blank dialog box.

Please show a more complete code snippet that actually compiles. I'm
guessing that you are not actually accessing the correct TIdTCPClient
instance that you think you are.

> It would help if that kind of thing were documented..

Have you actually looked at Indy's documentation yet?

http://www.indyproject.org/Sockets/Docs/index.EN.aspx

> After leaving IOHandler unassigned, it continues to throw exceptions:


> Simulator->TCPClient->IOHandler->WriteLn("foo!");
> ...results in an access violation.

All the more reason to suspect that you are accessing a different
TIdTCPClient instance than you initially configured.

> Any suggestions as to how I can actualy make this work? A C++
> example would be great.

It would be better if you would show your actual code. Then someone can
show you how to fix it.


Gambit


Dennis Cote

unread,
Jun 2, 2008, 1:27:09 PM6/2/08
to
Gene Buckle wrote:
>
> Any suggestions as to how I can actualy make this work? A C++ example would
> be great.
>

You might want to look at some of the samples at
http://www.atozed.com/indy/demos/10/index.EN.aspx or
http://www.indyproject.org/Sockets/Demos/index.EN.aspx

Nothing in C++ specifically, but you should be able to translate from
Delphi or C# fairly easily in most cases.

HTH
Dennis Cote

Gene Buckle

unread,
Jun 3, 2008, 1:53:34 PM6/3/08
to

Thanks Dennis. I read and re-read the docs and still couldn't make it work.
I threw it out and started using the "TTCPClient" control that came with
RAD Studio. Strangely enough (ok, not strangely, "typically"), there's no
documentation on it at all in the help files. I'd like to be able to
set a timeout value for the TTCPClient->Receiveln() method, but so far have
had no luck in locating such a thing.

For the record, TTcpClient worked as expected - set the host, the port and
call connect. *bing* it works.

I will examine the demos to see if there is anything I was missing in
my setup of TIdTCPClient, but I seriously doubt it.

thanks all.

Remy Lebeau (TeamB)

unread,
Jun 3, 2008, 2:57:52 PM6/3/08
to

"Gene Buckle" <ge...@grumble.deltasoft.com> wrote in message
news:4845...@newsgroups.borland.com...

> Thanks Dennis. I read and re-read the docs and still couldn't make it
> work.

What EXACTLY are you having trouble with? You haven't answered my last
message yet.

> I threw it out and started using the "TTCPClient" control that
> came with RAD Studio.

Ouch! That is a bad component to use, in my opinion. It was Borland's
attempt at a cross-platform socket component, but it was implemented very
poorly, requiring a lot of extra manual work on your part. I strongly
suggest staying away from it. Even Borland's TClientSocket is better to use
than TTcpClient.

> Strangely enough (ok, not strangely, "typically"), there's no
> documentation on it at all in the help files.

TTcpClient is a CLX component, not a VCL component. Did you look in the CLX
documentation?

> I'd like to be able to set a timeout value for the
> TTCPClient->Receiveln() method

TTcpClient does not expose any timeouts.

> but so far have had no luck in locating such a thing.

Because it doesn't exist in TTcpClient. You would have to call the socket
API's setsockopt() function directly instead, setting the SO_RCVTIMEO value.

> For the record, TTcpClient worked as expected - set the
> host, the port and call connect. *bing* it works.

So does TIdTCPClient when used properly. Again, please answer my last
message regarding that.


Gambit


Gene Buckle

unread,
Jun 3, 2008, 3:54:53 PM6/3/08
to
"Remy Lebeau \(TeamB\)" <no....@no.spam.com> wrote:
>

> "Gene Buckle" <ge...@grumble.deltasoft.com> wrote in message
> news:4845...@newsgroups.borland.com...
>
>> Thanks Dennis. I read and re-read the docs and still couldn't make it
>> work.
>
> What EXACTLY are you having trouble with? You haven't answered my last
> message yet.
>

That's because I gave up in disgust waiting for the powers that be to get
off the dime and fix the news server over the weekend. I changed the
code.



>> Strangely enough (ok, not strangely, "typically"), there's no
>> documentation on it at all in the help files.
>
> TTcpClient is a CLX component, not a VCL component. Did you look in the CLX
> documentation?
>

So I should assume that using the help system with the Filter set to
"(No Filter)" means that it'll show me everything EXCEPT the CLX help?

Let me do a search and see what shows up, because the index is empty
regarding TTCPClient.

Ahh, here we go:
"TTCPClient" <search>

Local Help (0)
MSDN Online (0)
Codezone Community (0)
Questions (0)

RAD Studio 2007 with latest help file patch applied.
Assume for a while that while I'm no where near a C++ expert, I'm by no means
an idiot. Give me a *little* credit. When I tell you there's no mention
of TTCPClient in the help file, don't assume I'm some stumbling half-wit CS
student that can't find the farking off button without a map and an assistant.


>
> So does TIdTCPClient when used properly. Again, please answer my last
> message regarding that.
>

Is this, or is this not the correct way to use TIdTCPClient:
(included files - I don't recall where I got this list from)

#include <IdBaseComponent.hpp>
#include <IdComponent.hpp>
#include <IdIOHandler.hpp>
#include <IdIOHandlerStream.hpp>
#include <IdTCPClient.hpp>
#include <IdTCPConnection.hpp>


TIdTCPClient *Client;
bool connected;

Client = new TIdTCPClient(NULL):

Client->Port = 5500;
Client->Host = "localhost";

Client->Connect();
connected = Client->Connected();

This is _EXACTLY_ how I'm using (or was) this library. If I'm missing a step
please enlighten me.


FYI, attached is the only copy I have of the code that still shows the use of
the TIdTCPClient component before I tore it out:

#pragma hdrstop

#include "classSimulator.h"
#include "defines.h"
#include "frmMain.h"

bool init_done;
__fastcall classSimulator::classSimulator() {
busy = false;
init_done = false;
}

__fastcall classSimulator::~classSimulator() {


}

void __fastcall classSimulator::InitCommSystem() {
if (!init_done) {
busy = true;
TCPClient = new TIdTCPClient(NULL);


TCPClient->OnDisconnected = MainForm->DisconnectHandler;

busy = false;
init_done = true;
}
}

bool __fastcall classSimulator::StartComms() {
// connects to the selected simulator

TCPClient->Port = 5500;
TCPClient->Host = "localhost";
try {
TCPClient->Connect();
return true;
} catch (Exception &ex) {
return false;
}

}

void __fastcall classSimulator::StopComms() {
// disconnects from the selected simulator
if (TCPClient->Connected()) {
TCPClient->Disconnect();
}
}

void __fastcall classSimulator::CloseCommSystem() {
TCPClient->Free();
}

bool __fastcall GetBoolValue(int function_code) {

}

void __fastcall SetBoolValue(int function_code, bool value) {


}

tnx.

Remy Lebeau (TeamB)

unread,
Jun 3, 2008, 4:37:34 PM6/3/08
to

"Gene Buckle" <ge...@grumble.deltasoft.com> wrote in message
news:4845...@newsgroups.borland.com...

> Is this, or is this not the correct way to use TIdTCPClient:

In general, yes. But earlier you showed that you are using it inside of a
classSimulator class. I'm more interested in seeing how THAT class is being
used. In particular, you also showed a call to ShowMessage(), but you did
not indicate WHERE that was being called from exactly. Can you please
provide a concrete compilable code snippet that demonstrates your problem in
a reproducable way?

> #include <IdIOHandlerStream.hpp>

Get rid of that one. You are not using it anymore.

> Client->Connect();
> connected = Client->Connected();

If Connect() fails, it will raise an exception. You do not need to call
Connected() immediately after Connect().

> FYI, attached is the only copy I have of the code that still shows
> the use of the TIdTCPClient component before I tore it out:

But you did not show how the classSimulator itself was being used.

> bool init_done;

You should always intialize your globals.

bool init_done = false;

> void __fastcall classSimulator::InitCommSystem() {
> if (!init_done) {
> busy = true;
> TCPClient = new TIdTCPClient(NULL);
> TCPClient->OnDisconnected = MainForm->DisconnectHandler;
>
> busy = false;
> init_done = true;
> }
> }

Where is TCPClient actually declared? Is it global, or is it a member of
classSimulator? Where is InitCommSystem() being called from?

> } catch (Exception &ex) {

You should always catch exceptions by 'const' reference instead:

} catch (const Exception &ex) {

> if (TCPClient->Connected()) {
> TCPClient->Disconnect();

You don't need to call Connected() first.

> void __fastcall classSimulator::CloseCommSystem() {
> TCPClient->Free();
> }

Where is CloseCommSystem() called from?

Never call Free() directly. Use 'delete' instead, especially since you used
'new' to allocate it. And be sure to reset your pointer back to NULL as
well:

void __fastcall classSimulator::CloseCommSystem()
{
delete TCPClient;
TCPClient = NULL;
}


Gambit


Gene Buckle

unread,
Jun 3, 2008, 5:21:32 PM6/3/08
to
"Remy Lebeau \(TeamB\)" <no....@no.spam.com> wrote:
>
> "Gene Buckle" <ge...@grumble.deltasoft.com> wrote in message
> news:4845...@newsgroups.borland.com...
>
>> Is this, or is this not the correct way to use TIdTCPClient:
>
> In general, yes. But earlier you showed that you are using it inside of a
> classSimulator class. I'm more interested in seeing how THAT class is being
> used. In particular, you also showed a call to ShowMessage(), but you did
> not indicate WHERE that was being called from exactly. Can you please
> provide a concrete compilable code snippet that demonstrates your problem in
> a reproducable way?
>

classSimulator is declared as a global in the code file that contains
WinMain().

It's declared:

classSimulator *Simulator;

Other files that reference it contain:

extern classSimulator *Simulator;

Note that the class functions perfectly in the absense of TIdTCPClient.

For example, in my main form, I execute this code:


Simulator->TCPClient->Sendln("data");
param_count = FunctionConfig->g_SimParams.size();
Simulator->busy = true; // I'm busy! Quit bugging me and get off my damn lawn! .
if (Simulator->g_SimParams.size() == 0) {
// we've not loaded this up yet...
for (zed = 0; zed < param_count; zed++) {
Application->ProcessMessages();
const string &key = FunctionConfig->g_SimParams.get(zed);
const string &value = FunctionConfig->g_SimParams.get(key);
cmd = value.c_str();
cmd = "get " + cmd;
Simulator->TCPClient->Sendln(cmd);
reply = Simulator->TCPClient->Receiveln('\n');
if (reply != '\r') {
Simulator->g_SimParams.set(value.c_str(),reply.c_str());
} else {
Simulator->g_SimParams.set(value.c_str(),"invalid");
}
}

}

This works flawlessly.

>
> But you did not show how the classSimulator itself was being used.
>

See above.

>> bool init_done;
>
> You should always intialize your globals.
>
> bool init_done = false;
>

You mean like I was doing in the constructor?:

__fastcall classSimulator::classSimulator() {
busy = false;
init_done = false;
SimulatorType = -1;
g_SimParams.clear();
g_SimParamsHold.clear();

}

>> void __fastcall classSimulator::InitCommSystem() {
>> if (!init_done) {
>> busy = true;
>> TCPClient = new TIdTCPClient(NULL);
>> TCPClient->OnDisconnected = MainForm->DisconnectHandler;
>>
>> busy = false;
>> init_done = true;
>> }
>> }
>
> Where is TCPClient actually declared? Is it global, or is it a member of
> classSimulator? Where is InitCommSystem() being called from?
>

It's declared in the header file for classSimulator. Like I mentioned earlier,
TCPClient is declared:

TIdTCPClient *TCPClient;

Where InitCommSystem() is being called from is irrelevant as it's simply a
a function and works as it should using TTCPClient:

void __fastcall classSimulator::InitCommSystem() {
if (!init_done) {
busy = true;

TCPClient = new TTcpClient(NULL);
TCPClient->OnDisconnect = MainForm->DisconnectHandler;

busy = false;
init_done = true;
}
}

>> } catch (Exception &ex) {
>
> You should always catch exceptions by 'const' reference instead:
>
> } catch (const Exception &ex) {
>

Noted, thanks. Why const?



>> if (TCPClient->Connected()) {
>> TCPClient->Disconnect();
>
> You don't need to call Connected() first.
>

Why bother calling Disconnect if I'm not connected to begin with? :)



>> void __fastcall classSimulator::CloseCommSystem() {
>> TCPClient->Free();
>> }
>
> Where is CloseCommSystem() called from?
>

Irrelevant.


> Never call Free() directly. Use 'delete' instead, especially since you used
> 'new' to allocate it. And be sure to reset your pointer back to NULL as
> well:
>
> void __fastcall classSimulator::CloseCommSystem()
> {
> delete TCPClient;
> TCPClient = NULL;
> }

Is there any valid instance to use Free() instead of delete?

Is there an example anywhere of a C++ program that uses TIdTCPClient that
actually works? I have seen _zero_ C++ examples for this library.
The documentation is written from the standpoint that everyone that sees
it must be a C++ master, therefore no examples are neccessary.

FYI, attached is the current version of classSimulator, both cpp and header.
It works without error.

#ifndef classSimulatorH
#define classSimulatorH

#include "cockpitmaster.h"


//#include <IdBaseComponent.hpp>
//#include <IdComponent.hpp>
//#include <IdIOHandler.hpp>
//#include <IdIOHandlerStream.hpp>
//#include <IdTCPClient.hpp>
//#include <IdTCPConnection.hpp>
#include <Sockets.hpp>

#include "classUnsortedMap.h"

#include <string>
#include <map>
#include <vector>

using namespace std;

typedef std::map<std::string,std::string> StringMap;

class classSimulator {
public:
__fastcall classSimulator();
__fastcall ~classSimulator();

void __fastcall InitCommSystem();
void __fastcall CloseCommSystem();

bool __fastcall StartComms();
void __fastcall StopComms();

bool __fastcall GetBoolValue(AnsiString function_name);

void __fastcall SetBoolValue(AnsiString function_name, bool value);

bool busy; // flag used to hold threads at bay until the current
// operation is completed.

AnsiString port;
AnsiString host;

TTcpClient *TCPClient;

int SimulatorType;

classUnsortedMap g_SimParams;
classUnsortedMap g_SimParamsHold;

private:

};


//---------------------------------------------------------------------------
#endif


#pragma hdrstop

#include "classSimulator.h"
#include "defines.h"
#include "frmMain.h"

bool init_done;

__fastcall classSimulator::classSimulator() {
busy = false;
init_done = false;
SimulatorType = -1;
g_SimParams.clear();
g_SimParamsHold.clear();

}

__fastcall classSimulator::~classSimulator() {


}

void __fastcall classSimulator::InitCommSystem() {
if (!init_done) {
busy = true;

TCPClient = new TTcpClient(NULL);
TCPClient->OnDisconnect = MainForm->DisconnectHandler;

busy = false;
init_done = true;
}
}

bool __fastcall classSimulator::StartComms() {


// connects to the selected simulator

if ((port == "") || (host == "")) {
return false;
}
TCPClient->RemotePort = port;
TCPClient->RemoteHost = host;
try {
if (TCPClient->Connect()) {
// sim specific connection processing?...
return true;
}
//return true;
} catch (const Exception &ex) {
ShowMessage(ex.Message);
return false;
}

}

void __fastcall classSimulator::StopComms() {
// disconnects from the selected simulator

if (TCPClient->Connected) {
TCPClient->Disconnect();
}
}

void __fastcall classSimulator::CloseCommSystem() {
delete TCPClient;
TCPClient = NULL;
}

bool __fastcall GetBoolValue(AnsiString function_name) {

}

void __fastcall SetBoolValue(AnsiString function_name, bool value) {

Remy Lebeau (TeamB)

unread,
Jun 3, 2008, 8:43:27 PM6/3/08
to

"Gene Buckle" <ge...@grumble.deltasoft.com> wrote in message
news:4845...@newsgroups.borland.com...

> It's declared in the header file for classSimulator. Like I


> mentioned earlier, TCPClient is declared:
>
> TIdTCPClient *TCPClient;

But, you still did not indicate where your ShowMessage() was being called
from. Again, the ONLY way ShowMessage(TCPClient->Host) could display an
empty dialog is if you had not actually assigned a non-empty string to the
Host property beforehand, indicating that you either did not initialize your
TIdTCPClient before calling SowMessage(), or that you called it using a
secondary TIdTCPClient instance that you did not configure. I'm trying to
get you to provide a code snippet that reproduces that original problem
again.


Gambit


Gene Buckle

unread,
Jun 3, 2008, 9:40:35 PM6/3/08
to
"Remy Lebeau \(TeamB\)" <no....@no.spam.com> wrote:
>
It doesn't matter. The control was being initialized before the ShowMessage().
I single stepped through the method that assigned Host and Port. You know
what I saw when I hovered my mouse cursor on the ->Host and ->Port properties?
NULL.

I gave you an ENTIRE class that illustrated the problem, which by the way
is the ONLY place that TIdTCPClient is referenced anywhere in my code.
You're so busy convincing yourself that I'm some stumbling idiot that can
hardly tie my own shoes let alone write software that you're no longer looking
at what is going on - if you had, you certainly wouldn't have chastised me for
not initializing a variable before using it when I was clearly doing so
in the constructor method of the class.

You're a brilliant guy Gambit, but you need to try to help people without the
air of superiority you exude. :)

In my research to see if I could get anything out of the control, I tried
polling the Version property to see if that had anything in it.

Here's where it gets weird - the version was 9.0.<something>! That would
go a long way toward explaining what is going on.

Any tips on how to get rid of an Indy9 that I never installed? :)

thanks. (really!)

g.

0 new messages