Re: [twsocket] DLL implementation advice (or example)...

2011-09-16 Thread Adam Burgoyne
Thanks for the explanation and example, Arno, but I was 1 step ahead of you
in realising the mistake.

What I did (which appears to have worked as the errors are not being
reported now) is to simply move the "Note" variable into the global scope.

The DLL only gets called by one external process so I think it's a
reasonably safe approach... unless you know different. :-)

Regards, Adam

-Original Message-
From: twsocket-boun...@elists.org [mailto:twsocket-boun...@elists.org] On
Behalf Of Arno Garrels
Sent: 16 September 2011 07:17
To: ICS support mailing
Subject: Re: [twsocket] DLL implementation advice (or example)...

Adam Burgoyne wrote:
> I've now changed the
> code to this which should solve the problem if I understood correctly:
> 
> function ReadMessage: PAnsiChar; stdcall; var
>  Note: AnsiString;
> begin
>  EnterCriticalSection(CritSectn);
> 
>  if (NotesList.Count > 0) then
>  begin
>Note := NotesList.Strings[0];
>NotesList.Delete(0);
>Result := PAnsiChar(Note);
>  end
>  else
>Result := '';
> 
>  LeaveCriticalSection(CritSectn);
> end;


That doesn't work either, the string assigned to the local variable is
destroyed when it goes out of scope, that is when the function is left.
You have to change the function like below and have the caller allocate and
free the memory the string is copied to:

{code untested}
function ReadMessage(pBuf: PAnsiChar; pBufSize: PLongWord): LongWord;
stdcall;
begin   
  try
EnterCriticalSection(CritSectn);
try
  if pBufSize = nil then
  begin
Result := 0;
  end
  else if pBuf = nil then
  begin // Return required size / number of AnsiChars
pBufSize^ := Length(NotesList[0]);
Result := 0;
  end
  else if pBufSize^ < Length(NotesList[0]) then
  begin // Return required size / number of AnsiChars
pBufSize^ := Length(NotesList[0]);
Result := 0;   
  end
  else begin // Return number of copied AnsiChars 
Result := Length(NotesList[0]);
Move(Pointer(NotesList[0])^, pBuf^, Result);
NotesList.Delete(0);
  end;
finally
  LeaveCriticalSection(CritSectn);
end;
  except
Result := 0;
  end;   
end;
{code}

But..
If that function is called from different threads you cannot use it to get
the size of a string in a first call with a nil pBuf since on the second
call the string might no longer be the same. 
   
--
Arno Garrels

--
To unsubscribe or change your settings for TWSocket mailing list please goto
http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be

--
To unsubscribe or change your settings for TWSocket mailing list
please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be


Re: [twsocket] DLL implementation advice (or example)...

2011-09-15 Thread Adam Burgoyne
Hi, Wilfried - thanks for the explanation - I've been looking at the code
for hours and just couldn't see the cause.  I've now changed the code to
this which should solve the problem if I understood correctly:

function ReadMessage: PAnsiChar; stdcall;
var
  Note: AnsiString;
begin
  EnterCriticalSection(CritSectn);

  if (NotesList.Count > 0) then
  begin
Note := NotesList.Strings[0];
NotesList.Delete(0);
Result := PAnsiChar(Note);
  end
  else
Result := '';

  LeaveCriticalSection(CritSectn);
end;


Regarding the critical section issue, there are 2 threads involved ... the
main DLL thread which services the calls from the client application and the
worker thread which is running the TWSocket message loop.

As I saw things, there were two areas that could be problematic:

1) the Readmessage function above which is checking the list count and
deleting the string after reading it.
2) the worker thread that would be trying to add strings to the end of a
list which might be 1 string shorter at the end of the process than it was
at the beginning i.e. the string count is 5 as the worker thread prepares to
add NotesList.Strings[5] but before that task has completed, the main thread
has deleted NotesList.Strings[0] so the count is then only 4

Is that a possibility or is the Strings class smart / thread-safe enough to
prevent those situations causing an issue?

Regards, Adam


-Original Message-
From: twsocket-boun...@elists.org [mailto:twsocket-boun...@elists.org] On
Behalf Of Wilfried Mestdagh
Sent: 15 September 2011 22:34
To: 'ICS support mailing'
Subject: Re: [twsocket] DLL implementation advice (or example)...

Hi Adam,

> despite tearing out some hair and losing a

Hopefully you have spare :)

> Result := PAnsiChar(NotesList.Strings[0]);
> NotesList.Delete(0);

The problem is that you give a pointer to the return value of that function
to something that not exists anymore after the functions exit:

> Result := PAnsiChar(NotesList.Strings[0]);

You give a pointer to a string

> NotesList.Delete(0);

And here you destroy the string you point to

> critical section code or not... I thought I might as the worker thread

You only need Critical section if you access same data from out different
thread context. So if this is not the case then you don't need it.

Was this clear to answer your questions?

--
mvg, Wilfried
http://www.mestdagh.biz
http://www.comfortsoftware.be
http://www.expertsoftware.be

--
To unsubscribe or change your settings for TWSocket mailing list please goto
http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be

--
To unsubscribe or change your settings for TWSocket mailing list
please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be


Re: [twsocket] DLL implementation advice (or example)...

2011-09-15 Thread Adam Burgoyne
Hi, All

Ok - first the good news... despite tearing out some hair and losing a good
few hours of sleep, my new TWSocket-based DLL with the worker thread is
working brilliantly :-)

Now for the bad news... I am getting some strange and intermittent
"corruption" of function return values.

I'm not sure if this is an issue related specifically to D7 but I've
experienced it calling an exported function within the DLL (resolved by not
exporting it) and now from my calling application (written in C++).

The problem only seems to arise when there is conversion between AnsiString
and PAnsiChar types in an exported function so I'm wondering if anyone else
has seen this behaviour and/or has a solution because I certainly can't see
what's wrong.

Essentially, the DLL has a global TStringList which I'm using as a message
buffer. The worker thread adds new lines to the end of the TStringList as
they are received from the server because the burst rate is far higher than
the calling application can process them. The calling application then
simply requests the 1st message in the list when it's ready for it and that
entry is then deleted from the TStringList so that all incoming messages get
processed in sequence.

The actual code I'm using is here:

function ReadMessage: PAnsiChar; stdcall;
begin
  EnterCriticalSection(CritSectn);

  if (NotesList.Count > 0) then
  begin
Result := PAnsiChar(NotesList.Strings[0]);
NotesList.Delete(0);
  end
  else
Result := '';

  OutputDebugStringA(Result);

  LeaveCriticalSection(CritSectn);
end;


Now, a typical entry added to the list would be something like (without the
quotes) "MESSAGE:Hello World!" or just "MESSAGE:".

The correct strings do seem to be getting added to the list as I'm
monitoring the messages using DebugView but, my calling application is
getting some return values truncated with one or two unprintable characters
after the truncated text. For example, "MESSAGE:" might be received as
"MESSAG<"

Here is a live example taken from the application log - the actual message
logged by the DLL (so should be the content of the TStringList entry) is
"TRADE:" but the calling application received "TRAD"

I've tried playing around with the return type i.e. PChar / PAnsiChar /
PWideChar but it makes no difference

Hopefully someone can provide a little insight as it's driving me crazy.

I'd also be grateful if anyone could confirm whether I actually need the
critical section code or not... I thought I might as the worker thread could
be trying to add a new string as the main thread was deleting string [0] but
I read a note somewhere on a Delphi site that TStringLists were thread-safe
so I'm a bit confused about it.

Regards, Adam


--
To unsubscribe or change your settings for TWSocket mailing list
please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be


Re: [twsocket] DLL implementation advice (or example)...

2011-09-11 Thread Adam Burgoyne
Hi, Wilfried

I'm pleased to say that I've made good progress with the system so far but
I'm not sure how to best implement server alternation.

Very simply, the current system works with a main server and a fail-over
server.

All initial connections are made to the main server (I have this part
working fine) but, if the main server is unavailable then clients will
attempt to connect to the fail-over server.

What I need the client to do is try connecting to the other server if the
current connection cannot be made within a few seconds or if the current
connection gets dropped for any reason.

I've started playing around with it but I'm not sure I'm doing things
correctly.

I saw a post (from you I think) in the ICS help that mentioned sending a
message from the "sessionclosed" procedure but it didn't specify what
message to send.

Is there a list of messages that can be used with ICS?

Regards, Adam


-Original Message-
From: twsocket-boun...@elists.org [mailto:twsocket-boun...@elists.org] On
Behalf Of Wilfried Mestdagh
Sent: 09 September 2011 09:04
To: 'ICS support mailing'
Subject: Re: [twsocket] DLL implementation advice (or example)...

Hi Adam,

> The problem is that the DLL is quite unstable so I was trying to use a 
> different approach and hoping to get better stability.

Are we talking about TWSocket in your second approach?

> Right now, I have the basic DLL test project running - it is 
> connecting to my server but the worker thread is not terminating so 
> either the server is not sending a response or the ondatareceived 
> event is not triggering.

I'm not sure if a TDatamodule is thread safe. Anyway I never used it. Note
that what you create in a constructor is in main thread context. You have to
create (and destroy) the components in the Execute method of that thread. If
you do not then you have a false thread.

--
mvg, Wilfried

--
To unsubscribe or change your settings for TWSocket mailing list please goto
http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be

--
To unsubscribe or change your settings for TWSocket mailing list
please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be


Re: [twsocket] DLL implementation advice (or example)...

2011-09-08 Thread Adam Burgoyne
Hi, Wilfried - thanks for replying :-)


I have an existing DLL that was written to use TClientSocket via a data
module. It has a kind of message pump but it works in reverse... it has a
timer thread that uses postmessage to trigger the main app to call a
ReadData function which checks the socket for received data, then processes
it.

The problem is that the DLL is quite unstable so I was trying to use a
different approach and hoping to get better stability.

Right now, I have the basic DLL test project running - it is connecting to
my server but the worker thread is not terminating so either the server is
not sending a response or the ondatareceived event is not triggering. The
current DLL had an issue with incoming data not being reported so I'm not
sure if this is a related problem.

I'll keep experimenting and hopefully I can get a working model soon :-)

Regards, Adam 


-Original Message-
From: twsocket-boun...@elists.org [mailto:twsocket-boun...@elists.org] On
Behalf Of Wilfried Mestdagh
Sent: 08 September 2011 22:42
To: 'ICS support mailing'
Subject: Re: [twsocket] DLL implementation advice (or example)...

Hi Adam,

> Hi - after pulling out a lot of hair

Hopefully you have some reserve :)

> I've spent the last couple of days tinkering with the DLL 1 example 
> but

DLL is not different from other. Only think is if you write a DLL you maybe
don't know who call it. Maybe a programmer will use the DLL wich has no
knowledge of message pump or the way windows work. Maybe you have to write
your own message pump in that case.

> Connect() needs to be passed the host, the port, the username, the

If you have a working message pump then after a connection then
OnSessionconnected will fire. Then you have it all.

> What I need Connect() to do is kick off a worker thread that continues 
> running and manages the socket connection without blocking the calling 
> process as the current DLL example does.

I'm not sure wy do you need a separate worker thread?

> 2)  SendStr() the username

SendStr is what you can do in the OnSessionConnected event

> .then sit in a loop where it:

You don't need a loop! TWSocket is event driven (fortinatly)

> 3)  Monitors for incoming messages and adds each message to a
> TStringList

Every receved data you can add. Note that TCP is NOT package bound garantie.

> 4)  Fires off a PostMessage() to the specified window of the main
> application every "pump rate" milliseconds

You can give the handle to the window to the DLL from the calling
application.

> Connected() simply returns the connection status of the socket
> GetMessage() returns information from the TStringList
> Disconnect() signals the worker thread to gracefully drop the 
> connection (if
> possible) and close down

Just call the right TWSocket methods

> One of the difficulties seems to be that the socket would be running 
> within the worker thread but the functions and data that I need to 
> access would be in the global scope.

If you are certain you need a separate thread then you can use PostMessage
(or SendMessage)

--
mvg, Wilfried
http://www.mestdagh.biz
http://www.comfortsoftware.be
http://www.expertsoftware.be


--
To unsubscribe or change your settings for TWSocket mailing list
please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be

--
To unsubscribe or change your settings for TWSocket mailing list
please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be


[twsocket] DLL implementation advice (or example)...

2011-09-08 Thread Adam Burgoyne
Hi - after pulling out a lot of hair, I'm hoping someone can take pity on a
poor, struggling programmer who needs some help J

 

I'm not a beginner with Delphi but I'm definitely not an expert either so
I'm really struggling to create a DLL-based WSocket client that does what I
need.

 

I've spent the last couple of days tinkering with the DLL 1 example but just
can't get it to function so I'm hoping that someone can assist.

 

Basically what I'm trying to do is implement 4 functions that can be called
safely from my app:

 

Connect(), Connected(), Disconnect() and GetMessage()

 

Connect() needs to be passed the host, the port, the username, the handle of
the calling child window and a "pump rate"

 

What I need Connect() to do is kick off a worker thread that continues
running and manages the socket connection without blocking the calling
process as the current DLL example does.

 

That worker thread should:

1)  Connect the socket to the host

2)  SendStr() the username

 

.then sit in a loop where it:

3)  Monitors for incoming messages and adds each message to a
TStringList

4)  Fires off a PostMessage() to the specified window of the main
application every "pump rate" milliseconds

 

 

Connected() simply returns the connection status of the socket

 

GetMessage() returns information from the TStringList

 

Disconnect() signals the worker thread to gracefully drop the connection (if
possible) and close down

 

 

>From the application perspective, it would call the Connect() function,
monitor the connection status via Connected(), obtain incoming messages via
GetMessage() and call Disconnect() as required.

 

One of the difficulties seems to be that the socket would be running within
the worker thread but the functions and data that I need to access would be
in the global scope.

 

As I said, I'm hoping someone can help me with this - I know what I need it
to do but seem to have passed the point where my coding skills let me do it.

 

Regards, Adam

 

 

--
To unsubscribe or change your settings for TWSocket mailing list
please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be


[twsocket] DLL implementation advice (or example)...

2011-09-08 Thread Adam Burgoyne
Not sure if this was accepted first attempt as I cleverly mailed from the
wrong email address!

 

Hi - after pulling out a lot of hair, I'm hoping someone can take pity on a
poor, struggling programmer who needs some help J

 

I'm not a beginner with Delphi but I'm definitely not an expert either so
I'm really struggling to create a DLL-based WSocket client that does what I
need.

 

I've spent the last couple of days tinkering with the DLL 1 example but just
can't get it to function so I'm hoping that someone can assist.

 

Basically what I'm trying to do is implement 4 functions that can be called
safely from my app:

 

Connect(), Connected(), Disconnect() and GetMessage()

 

Connect() needs to be passed the host, the port, the username, the handle of
the calling child window and a "pump rate"

 

What I need Connect() to do is kick off a worker thread that continues
running and manages the socket connection without blocking the calling
process as the current DLL example does.

 

That worker thread should:

1)  Connect the socket to the host

2)  SendStr() the username

 

.then sit in a loop where it:

3)  Monitors for incoming messages and adds each message to a
TStringList

4)  Fires off a PostMessage() to the specified window of the main
application every "pump rate" milliseconds

 

 

Connected() simply returns the connection status of the socket

 

GetMessage() returns information from the TStringList

 

Disconnect() signals the worker thread to gracefully drop the connection (if
possible) and close down

 

 

>From the application perspective, it would call the Connect() function,
monitor the connection status via Connected(), obtain incoming messages via
GetMessage() and call Disconnect() as required.

 

One of the difficulties seems to be that the socket would be running within
the worker thread but the functions and data that I need to access would be
in the global scope.

 

As I said, I'm hoping someone can help me with this - I know what I need it
to do but seem to have passed the point where my coding skills let me do it.

 

Regards, Adam

 

 

--
To unsubscribe or change your settings for TWSocket mailing list
please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket
Visit our website at http://www.overbyte.be