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

2011-09-17 Thread Francois PIETTE
I see. The idea is the usage of the widestring just as a easy way to call 
the, behind the scene, SysAllocString and SysFreeString, that we need in 
this case. But we can always treat it as a buffer, setting its length, and 
moving data, explicitly, without casting.


In my opinion, it is ALWAYS a bad idea to use a string variable (whatever 
string flavour it is) to store anything else than actual text data.



francois.pie...@overbyte.be
The author of the freeware multi-tier middleware MidWare
The author of the freeware Internet Component Suite (ICS)
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-17 Thread RTT

On 17-09-2011 09:56, Francois PIETTE wrote:
I see. The idea is the usage of the widestring just as a easy way to 
call the, behind the scene, SysAllocString and SysFreeString, that we 
need in this case. But we can always treat it as a buffer, setting 
its length, and moving data, explicitly, without casting.


In my opinion, it is ALWAYS a bad idea to use a string variable 
(whatever string flavour it is) to store anything else than actual 
text data.


Yep, but without a better data type, with the same, behind the scenes, 
allocation/reallocation/deallocation/... magic, make it handy, even if 
potentially problematic, if not used correctly.


Another method that should work for this problem, and that maintain some 
of the magic of the WideString method.


DLL
__

 iRawData = interface(IInterface)
function getData: string;
procedure setData(data:string);
property data:string read getData write setData;
  end;

   function ReadMessage(msg:iRawData):boolean; stdcall;
   begin
 EnterCriticalSection(CritSectn);

 if (NotesList.Count  0) then
 begin
   msg.data := NotesList.Strings[0];
   NotesList.Delete(0);
   Result := true;
 end
 else
   Result := false;

 LeaveCriticalSection(CritSectn);
   end;


APP
__

 iRawData = interface(IInterface)
function getData: string;
procedure setData(data:string);
property data:string read getData write setData;
  end;

  TRawData = class(TInterfacedObject, iRawData)
fdata: string;
function getData: string;
procedure setData(data:string);
  end;

   function ReadMessage(msg:iRawData):boolean; stdcall; external
   MyDll.dll
   ...
   ...
   var
   msg:iRawData;
   begin
msg:=TRawData .create; //this initialization need is the only
   annoying thing
if ReadMessage(msg) then
something:=msg.data;
   end;


I'm using a string as data older because in this specif case the data 
source is a string too.
I'm excluding the TRawData implementation here, but there is nothing 
special about it.



--
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-16 Thread Arno Garrels
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


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-16 Thread Arno Garrels
Adam Burgoyne wrote:
 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. :-)

The number of processes doesn't matter since each loads its private 
copy of the DLL. However since your exported function seems to be
called by multiple threads of the same host process you may not use
a global variable since that won't be thread-safe.

-- 
Arno Garrels
   

 
 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-16 Thread RTT

I think you could also use a WideString var parameter.

function ReadMessage(var msg:WideString):boolean; stdcall;
var
 Note: AnsiString;
begin
 EnterCriticalSection(CritSectn);

 if (NotesList.Count  0) then
 begin
   msg := NotesList.Strings[0];
   NotesList.Delete(0);
   Result := true;
 end
 else
   Result := false;

 LeaveCriticalSection(CritSectn);
end;




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



--
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-16 Thread Arno Garrels
RTT wrote:
 I think you could also use a WideString var parameter.

That would work which plain text, but it's slow..
I bet it's slower than one more copy of the result string.
Also using WideString leads to implicit string casts, 
without any warning in Delphi versions  2009, which is
error-prone. 

-- 
Arno Garrels
  
 
 function ReadMessage(var msg:WideString):boolean; stdcall;
 var
  Note: AnsiString;
 begin
  EnterCriticalSection(CritSectn);
 
  if (NotesList.Count  0) then
  begin
msg := NotesList.Strings[0];
NotesList.Delete(0);
Result := true;
  end
  else
Result := false;
 
  LeaveCriticalSection(CritSectn);
 end;
 
 
 
 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
--
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-16 Thread RTT

On 16-09-2011 18:58, Arno Garrels wrote:

That would work which plain text
Why your reference to plaint text? A WideString can carry any data, or 
I'm missing something?


And WideStrings are now relatively fast, in Vista and 7, if compared to XP.

But I really don't know if two calls, one to get the size and another to 
get the data, with the two related EnterCriticalSection, is faster.
And if a EnterCriticalSection is being used, I suppose it is because the 
data can change, so there is the potential the first call to get the 
size is no longer valid when requesting the data itself.

--
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-16 Thread Arno Garrels
RTT wrote:
 On 16-09-2011 18:58, Arno Garrels wrote:
 That would work which plain text
 Why your reference to plaint text? A WideString can carry any data,
 or I'm missing something?

As far as I read this thread the OP uses a non-Unicode Delphi version.
So string maps to AnsiString. Any assignment of an AnsiString to a 
WideString leads to an implicit string cast to Unicode (Win API 
WideCharToMultiByte) internally, that's one of the compiler 'magics'
included in Delphi. Converting from Ansi to Unicode and back again to
Ansi however doesn't work reliable with arbitrary binary data but only
with pure _textual data, it depends on the current Ansi codepage whether
or not some non-printable chars are converted back and forth without
data loss.

 
 And WideStrings are now relatively fast, in Vista and 7, if compared
 to XP. 

I agree that WideString might be a workaround in some cases as long as
we have to handle text.
 
 But I really don't know if two calls, one to get the size and another
 to get the data, with the two related EnterCriticalSection, is faster.

One could, i.e., make sure that the recieved string length doesn't 
exceed a maximum and use a single call with a constant sized buffer
in order to avoid double calls.

 And if a EnterCriticalSection is being used, I suppose it is because
 the data can change, so there is the potential the first call to get
 the 
 size is no longer valid when requesting the data itself.

I think I mentioned that, no?

-- 
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


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

2011-09-16 Thread RTT

On 16-09-2011 20:20, Arno Garrels wrote:
As far as I read this thread the OP uses a non-Unicode Delphi version. 
So string maps to AnsiString. Any assignment of an AnsiString to a 
WideString leads to an implicit string cast to Unicode (Win API 
WideCharToMultiByte) internally, that's one of the compiler 'magics' 
included in Delphi. Converting from Ansi to Unicode and back again to 
Ansi however doesn't work reliable with arbitrary binary data but only 
with pure _textual data, it depends on the current Ansi codepage 
whether or not some non-printable chars are converted back and forth 
without data loss. 


I see. The idea is the usage of the widestring just as a easy way to 
call the, behind the scene, SysAllocString and SysFreeString, that we 
need in this case. But we can always treat it as a buffer, setting its 
length, and moving data, explicitly, without casting.



One could, i.e., make sure that the recieved string length doesn't
exceed a maximum and use a single call with a constant sized buffer
in order to avoid double calls.


That would work too, and it's probably the better choice, if the 
function gets called many times. Allocate once, use many times.



And if a EnterCriticalSection is being used, I suppose it is because
the data can change, so there is the potential the first call to get
the
size is no longer valid when requesting the data itself.

I think I mentioned that, no?


Sorry, my fault. I missed to scroll your reply till the end. I stopped 
in the code sample :-(

--
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 Wilfried Mestdagh
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


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-11 Thread Wilfried Mestdagh
Hi Adam,

You have to make a custom message handler and post a message to it. Then
this handler will execute outside the event. Something like this:

const
WM_RECONNECT = WM_USER + 1;
private
procedure WMReconnect(var Msg: TMessage); message WM_RECONNECT;

procedure TSomething.SocketSessionClosed;
begin
PostMessage(Handle, WM_RECONNECT, 0 , 0);

If your TSomething does not have a Handle then you have to create one with
AllocateHWND procedure (and free it later) and you have to make a WinProc
procedure.

If it is threaded code then you also have to make a message pump. Please ask
if something is not clear.

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


 -Oorspronkelijk bericht-
 Van: twsocket-boun...@elists.org [mailto:twsocket-boun...@elists.org]
 Namens Adam Burgoyne
 Verzonden: zondag 11 september 2011 16:42
 Aan: 'ICS support mailing'
 Onderwerp: Re: [twsocket] DLL implementation advice (or example)...
 
 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

--
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-09 Thread Wilfried Mestdagh
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


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

2011-09-09 Thread Anton S.
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.
It's a really overcomplicated one!
I'd recommend you to isolate main app objects/variables from DLL ones as 
strongly as possible.
For example:

* Main app calls DLL's Connect() with a pointer to callback method.
* DLL's Connect() saves this pointer, allocates buffer for data and connects to 
the host specified
* In OnDataAvailable DLL copies data to buffer and calls the callback with 
parameters (PBufStart: PByte; PDataLen: Integer).
* Callback copies data to application's buffer thread-safely (you'll have to 
use additional thread for socket messages otherwise you'll get funny side 
effect when DLL's Socket.MessageLoop processes main app's messages) and signals 
main app thread to process the data received. Callback should return number of 
bytes it has read so that DLL could move a pointer to data start in the buffer.

In general, only simple and cross-language types should be used when 
interacting with DLL. This means NO CLASSES in parameters/results!

-- 
Anton
--
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-09 Thread Angus Robertson - Magenta Systems Ltd
 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 wrote an ActiveX DLL about 10 years ago that's still used on my web
site today, doing a reverse DNS look-up on the remote IP address that is
then displayed on the web page.  

It uses normal async ICS components, with a message loop to process the
messages. It is designed with a timeout, so it does not delay the page
been displayed too long if there is not DNS response, but it's easy to
change the main message loop to run until a 'disconnect' flag is set.
The ResultList variable is set in the OnDnsLookupDone event. 
I have an array of sockets so multiple requests can be handled. 

// start lookup
ResultList [mysocket] := '' ;
WSockets [mysocket].ReverseDnsLookup (IPAddr) ;

// now wait for lookup to complete or timeout after X seconds
   if (Timeout = 0) or (Timeout  10) then Timeout := LookupTimeout ;
   WaitTickList [mysocket] := GetTickCount + LongWord (Timeout * 1000) ;
   while ResultList [mysocket] = '' do
   begin
if GetTickCount = WaitTickList [mysocket] then
begin
   try
   WSockets [mysocket].Abort ;
   except
   end ;
   ResultList [mysocket] := '(Lookup Timed Out)' ;
   end ;
   WSockets [mysocket].ProcessMessages ;
   Sleep (0) ;
   end ;

Angus

--
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 Wilfried Mestdagh
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