Re: [twsocket] DLL implementation advice (or example)...
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)...
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)...
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)...
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)...
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)...
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)...
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)...
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)...
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)...
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)...
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)...
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)...
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)...
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)...
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)...
> 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)...
>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)...
Adam, you should read my recent message called "ICS in DLL. My report about results" here in mail list. I faced with tons of troubles because of DLL nature so finally I returned to my own blocking socket classes (just a simple WinSock wrapper - fortunately I needed only basic functions in DLL). For client library it works flawlessly. For server and complicated client apps I continue using ICS. -- 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)...
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)...
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
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