Answered by:
TcpClient Receives Data when Debugging Not When Compiled

Question
-
I have a program that waits for in incoming TCP connection and receives a chunk of data, the forwards it on to another server with some modifications. While I am debugging the program within Visual Studio everything works as intended. When I build the program and run it, it accepts the inbound connection and thinks there is data available... but when it reads in the stream there is no data. I cannot identify the problem, since it works fine while debugging. I have tried this on multiple servers (both x86 and x64) and get the same result. I have compiled in both debug and release. I'm using Visual Studio 2010.
Dim tmpLastMessageID As String = Nothing tcpsvr = New TcpListener(System.Net.IPAddress.Any, My.Settings.ListenPort) Try tcpsvr.Start() Catch ex As Exception Dim li As New ListViewItem(Now.ToString) li.SubItems.Add(ex.Message) lstHL7.Items.Add(li) Exit Sub End Try While ExitThread = False Try Dim tcpclient As TcpClient = tcpsvr.AcceptTcpClient If tcpclient.Connected Then Dim stream As NetworkStream = tcpclient.GetStream If stream.DataAvailable Then 'receive message Dim bytes(tcpclient.ReceiveBufferSize) As Byte stream.Read(bytes, 0, CInt(tcpclient.ReceiveBufferSize)) Dim data As String = Encoding.ASCII.GetString(bytes) Dim tmpString As String() = Split(data, "|") 'add date stamp Dim tmpDate As String = Mid(tmpString(6), 1, 8) tmpString(13) = tmpString(13) & "||" & tmpDate If tmpString(23) <> tmpLastMessageID Then 'send to new location tmpLastMessageID = tmpString(23) data = Join(tmpString, "|") Dim tmpMsg As String = data Dim tcpSend As New TcpClient(My.Settings.SendToIPAddress, My.Settings.SendToPort) Dim sendStream As NetworkStream = tcpSend.GetStream Dim msg As [Byte]() = System.Text.Encoding.ASCII.GetBytes(data) sendStream.Write(msg, 0, msg.Length) Do Until sendStream.DataAvailable Threading.Thread.Sleep(10) Loop ' send ack back Dim ACKbytes(tcpSend.ReceiveBufferSize) As Byte sendStream.Read(ACKbytes, 0, CInt(tcpSend.ReceiveBufferSize)) data = Encoding.ASCII.GetString(ACKbytes) data = data.ToUpper() stream.Write(ACKbytes, 0, ACKbytes.Length) sendStream.Close() sendStream.Dispose() tcpSend.Close() 'log it Dim li As New ListViewItem(Now.ToString) li.SubItems.Add(tmpMsg) tmpListofHL7.Add(li) tmpMsg = Nothing End If stream.Close() stream.Dispose() tcpclient.Close() tcpclient = Nothing End If End If Catch ex As Exception Dim li As New ListViewItem(Now.ToString) li.SubItems.Add(ex.Message) tmpListofHL7.Add(li) End Try End While End Sub
** All programmers are playwrights, and all computers are lousy actors.
Answers
-
I just dropped in a sleep after the client connects to allow the stream to fill up.... from what I can tell this seems to have solved the issue. I'm still going to do some more extensive testing, but for now the messages appear to be coming through. Turns out that the CVIS vendor indicated that he noticed when sending the charge messages they go out right away, but that the credit messages hang in a 'processing' state for a little bit before going. I think their interface was connecting, and starting to send the message while it's still being processed on their side adding a few millisecond delay to those messages.
** All programmers are playwrights, and all computers are lousy actors.
Well hopefully that resolves the issue though I would hate to rely on a timer like that in the process since it seems "out of place" used in that way for two reasons. First it halts the thread for the specified time period which is bad and second it may not incorporate a long enough time in it for some instances. I would think that there could be an if data present then type of scenario used to resolve this or a while data is not present loop type of scenarion. After all network data goes out in a framed format over the hardware layers so it's possible to have a busy network and the time extend past 100 miliseconds on the hardware layer alone I would guess but I may be way off on that estimate since I just pinged google and it took only 75 to 80 milliseconds including the round trip delay.
But I still despise that thread sleep timer. :(
You've taught me everything I know but not everything you know.
- Proposed as answer by Mr. Monkeyboy Friday, February 1, 2013 9:24 PM
- Marked as answer by Youen ZenModerator Monday, February 11, 2013 8:28 AM
All replies
-
-
I got a TCP transmitter and listener from this link http://www.eggheadcafe.com/articles/20020323.asp and was able to transmit from my laptop to my laptop with no problemo. However when I tried using the transmitter to transmit to your listener nothing happens in debug mode or not.
Here's the code, updated to correct some depricated information (I'm using VS 2012 and .Net 4.5).
Transmitter
Imports System.Net.Sockets Imports System.Text Public Class Form1 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim tcpClient As New System.Net.Sockets.TcpClient() tcpClient.Connect("192.168.0.13", 8000) Dim networkStream As NetworkStream = tcpClient.GetStream() If networkStream.CanWrite And networkStream.CanRead Then ' Do a simple write. Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes("Is anybody there" & vbCrLf) networkStream.Write(sendBytes, 0, sendBytes.Length) ' Read the NetworkStream into a byte buffer. Dim bytes(tcpClient.ReceiveBufferSize) As Byte networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize)) ' Output the data received from the host to the console. Dim returndata As String = Encoding.ASCII.GetString(bytes) RichTextBox1.AppendText("Host returned: " & returndata & vbCrLf) Else If Not networkStream.CanRead Then RichTextBox1.AppendText("cannot not write data to this stream" & vbCrLf) tcpClient.Close() Else If Not networkStream.CanWrite Then RichTextBox1.AppendText("cannot read data from this stream" & vbCrLf) tcpClient.Close() End If End If End If End Sub Private Sub RichTextBox1_TextChanged(sender As Object, e As EventArgs) Handles RichTextBox1.TextChanged End Sub End Class
Receiver
Imports System.Net.Sockets Imports System.Text Imports System.Net Public Class Form1 'http://www.eggheadcafe.com/articles/20020323.asp Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Dim ipAddress As IPAddress = ipAddress.Parse("192.168.0.13") Dim portNumber As Integer = 8000 Dim tcpListener As New TcpListener(ipAddress, portNumber) tcpListener.Start() RichTextBox1.AppendText("Waiting for connection..." & vbCrLf) Try 'Accept the pending client connection and return 'a TcpClient initialized for communication. Dim tcpClient As TcpClient = tcpListener.AcceptTcpClient() RichTextBox1.AppendText("Connection accepted.") ' Get the stream Dim networkStream As NetworkStream = tcpClient.GetStream() ' Read the stream into a byte array Dim bytes(tcpClient.ReceiveBufferSize) As Byte networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize)) ' Return the data received from the client to the console. Dim clientdata As String = Encoding.ASCII.GetString(bytes) RichTextBox1.AppendText(("Client sent: " + clientdata)) Dim responseString As String = "Connected to server." Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(responseString) networkStream.Write(sendBytes, 0, sendBytes.Length) RichTextBox1.AppendText(("Message Sent /> : " + responseString)) 'Any communication with the remote client using the TcpClient can go here. 'Close TcpListener and TcpClient. tcpClient.Close() tcpListener.Stop() RichTextBox1.AppendText("exit") Catch ex As Exception RichTextBox1.AppendText(ex.Message) End Try End Sub Private Sub RichTextBox1_TextChanged(sender As Object, e As EventArgs) Handles RichTextBox1.TextChanged End Sub End Class
You've taught me everything I know but not everything you know.
- Edited by Mr. Monkeyboy Thursday, January 31, 2013 1:30 AM
-
I again tried you code and changed it up a bit. It would'nt work. Then I added of all things some RichTextBox.AppendText entries in it to see where it was stopping and as soon as I added one to the Form Load event it started working.
I was able to send to it using my TCP transmitter. I sent something like "This is a test | of invalid data." to at least get the parser to work which it did and stopped at that point.
Then I changed what the text in the appendtext entries said and all of the sudden it quit working again. When I press Button1 even the first RichTextBox.AppendText entry does absolutely nothing although the Form Load RichTextBox1.Append text entry still works.
UPDATE: It's working continually. The problem was my Firewall was blocking after each time I reset my P/C trying to figure out the problem. It's working in both debug mode and straight up as an application.
In the image at the bottom you can see I sent to it using the TCP transmitter I showed in the previous post. The first Image is prior to transmission after your codes button has been pressed. The second Image is after I transmit to your application.
VS 2012, Win 7 64bit laptop.
Imports System.Text Imports System.Net.Sockets Imports System.Net Public Class Form1 Dim Test As Boolean = False Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load RichTextBox1.AppendText("Made it -1" & vbCrLf) End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click RichTextBox1.AppendText("Made it 0" & vbCrLf) Try RichTextBox1.AppendText("Made it 1" & vbCrLf) Dim tmpLastMessageID As String = Nothing RichTextBox1.AppendText("Made it 2" & vbCrLf) Dim ipAddress As IPAddress = ipAddress.Parse("192.168.0.13") RichTextBox1.AppendText("Made it 3" & vbCrLf) Dim tcpsvr As New TcpListener(ipAddress, 8000) RichTextBox1.AppendText("Made it 4" & vbCrLf) tcpsvr.Start() RichTextBox1.AppendText("Waiting for connection..." & vbCrLf) While Test = False Dim tcpclient As TcpClient = tcpsvr.AcceptTcpClient() RichTextBox1.AppendText("Connection accepted." & vbCrLf) If tcpclient.Connected Then Dim stream As NetworkStream = tcpclient.GetStream() If stream.DataAvailable Then 'receive message Dim bytes(tcpclient.ReceiveBufferSize) As Byte stream.Read(bytes, 0, CInt(tcpclient.ReceiveBufferSize)) Dim data As String = Encoding.ASCII.GetString(bytes) RichTextBox1.AppendText("Client sent: " & data & vbCrLf) Dim tmpString As String() = Split(data, "|") For Each Item In tmpString RichTextBox1.AppendText("Split data: " & Item & vbCrLf) Next 'add date stamp Dim tmpDate As String = Mid(tmpString(6), 1, 8) tmpString(13) = tmpString(13) & "||" & tmpDate If tmpString(23) <> tmpLastMessageID Then 'send to new location tmpLastMessageID = tmpString(23) data = Join(tmpString, "|") Dim tmpMsg As String = data Dim tcpSend As New TcpClient tcpSend.Connect("192.168.1.13", 8000) Dim sendStream As NetworkStream = tcpSend.GetStream Dim msg As [Byte]() = System.Text.Encoding.ASCII.GetBytes(data) sendStream.Write(msg, 0, msg.Length) Do Until sendStream.DataAvailable Threading.Thread.Sleep(10) Loop ' send ack back Dim ACKbytes(tcpSend.ReceiveBufferSize) As Byte sendStream.Read(ACKbytes, 0, CInt(tcpSend.ReceiveBufferSize)) data = Encoding.ASCII.GetString(ACKbytes) data = data.ToUpper() stream.Write(ACKbytes, 0, ACKbytes.Length) sendStream.Close() sendStream.Dispose() tcpSend.Close() 'log it Dim li As New ListViewItem(Now.ToString) li.SubItems.Add(tmpMsg) ListView1.Items.Add(li) tmpMsg = Nothing End If stream.Close() stream.Dispose() tcpclient.Close() tcpclient = Nothing End If End If End While Catch ex As Exception RichTextBox1.AppendText(ex.Message & vbCrLf) End Try End Sub Private Sub RichTextBox1_TextChanged(sender As Object, e As EventArgs) Handles RichTextBox1.TextChanged End Sub Private Sub ListView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView1.SelectedIndexChanged End Sub End Class
You've taught me everything I know but not everything you know.
- Edited by Mr. Monkeyboy Thursday, January 31, 2013 4:36 AM
-
-
Wow! Thank you so much for all your work on this question! I'm working with data from our CVIS system which sends in HL7. There are "Charges" and "Credits" that are sent in a batch format. The messages are received fine for both these types while debugging. When I compile the code, I'm still able to receive the "Charges", however the "Credits" just show up as an empty message (I think with a single control character at the begining.) When I have the vendor point the messages to a freeware HL7 Listener, both types of messages show up fine. When running the compiled version however, only the credits don't show.
I am super confused by this, as I've never seen this type of behavior before, and I uncertain how to debug the problem at this point. I'm thinking about scratching this project and building it up again from scratch in a new project. Since the code seems to be stable enough (thanks for taking a look at it), it must be something else I guess??
I have this section of the code running as a thread. I can't imagine that it makes any difference, but maybe I'll try running it directly instead?
** All programmers are playwrights, and all computers are lousy actors.
-
I don't get it. So in precompile mode, which I assume is on a test machine, receiving the data everything is fine and in postcompile mode, which I assume is STILL on the same test machine, receiving the data you receive "Charges" but not "Credits"? Perhaps you could post the preparsed data from a "Charges" and a "Credits" reception so I could test that out with my setup?
You've taught me everything I know but not everything you know.
-
Exactly! Weird right? Both messages work great while in debug mode.... but not when compiled. I'm wondering if I may need to sleep the thread a little. In debug mode, often I have a break where I stop the processing and advance line by line to check what is doing. Maybe something is running to fast in the compiled version? I'm going to test that theory now.
Messages below... it looks like it may not be pasting in the control characters that are required at the start, line break and end of the HL7 message.... the only difference between the messages is the switch in FT1 position 6 where it is a CG for charge and a CD for credit. Otherwise the messages are pretty much the same thing.
Charge Message:
FHS|^~\&|CVIS|CVIS|SAV|SAV|20130130083006|
BHS|^~\&|CVIS|CVIS|SAV|SAV|20130130083006|
MSH|^~\&|CVIS|CVIS|SAV|SAV|20130130083006||DFT^P03|2013013008300613763|P|2.3|||AL|||Windows-1252|
EVN|P03|20130130083006|
PID|||H0000283||BAR^CATHTEST1^^^||19800113|M||U|^^SALINAS^CA^93901^|||||||H00000605|||||
PV1||O|^^^||||||||||||||||H00000605|||||||||||||||||||||||||20130114093900|
FT1||||20130114|20130130083005|CG|24100054^REVISION OR RELOCATION OF PACEMAKER POCKET|REVISION OR RELOCATION OF PACEMAKER POCKET||1|||CAR|||^^^|||||ABURNSID^Burnsides^Aaron^^^||130.001SAV|
FT1||||20130114|20130130083005|CG|24100039^PACEMAKER GENERATOR INSERTION W/ EXISTING DUAL LEADS|PACEMAKER GENERATOR INSERTION W/ EXISTING DUAL LEADS||1|||CAR|||^^^|||||ABURNSID^Burnsides^Aaron^^^||130.001SAV|
FT1||||20130114|20130130083005|CG|22000206^BALLOON TREK OR MINI TREK |BALLOON TREK OR MINI TREK ||1|||CAR|||^^^|||||ABURNSID^Burnsides^Aaron^^^||130.001SAV|
FT1||||20130114|20130130083005|CG|24700002^EP CATHETER DUO DEC LIVEWIRE 7FR |EP CATHETER DUO DEC LIVEWIRE 7FR ||1|||CAR|||^^^|||||ABURNSID^Burnsides^Aaron^^^||130.001SAV|
MSH|^~\&|CVIS|CVIS|SAV|SAV|20130130083006||DFT^P03|2013013008300690326|P|2.3|||AL|||Windows-1252|
EVN|P03|20130130083007|
PID|||H0000284||BAR^CATHTEST2^^^||19820101|M||U|^^SALINAS^CA^93939^|||||||H00000606|||||
PV1||O|^^^||||||||||||||||H00000606|||||||||||||||||||||||||20130114094000|
FT1||||20130114|20130130083006|CG|24100003^COMPREHENSIVE EP EVALUATION W/LV PACING \T\ RECORDING (VT BASELINE + LV)|COMPREHENSIVE EP EVALUATION W/LV PACING \T\ RECORDING (VT BASELINE + LV)||1|||CAR|||^^^|||||ABURNSID^Burnsides^Aaron^^^||131.001SAV|
FT1||||20130114|20130130083006|CG|24100050^REPAIR OF ONE ELECTRODE SINGLE PACER/ICD|REPAIR OF ONE ELECTRODE SINGLE PACER/ICD||1|||CAR|||^^^|||||ABURNSID^Burnsides^Aaron^^^||131.001SAV|
FT1||||20130114|20130130083006|CG|22000536^ROTABLATER BURR |ROTABLATER BURR ||1|||CAR|||^^^|||||ABURNSID^Burnsides^Aaron^^^||131.001SAV|
FT1||||20130114|20130130083006|CG|22000402^BALLOON ANGIOSCULPT|BALLOON ANGIOSCULPT||1|||CAR|||^^^|||||ABURNSID^Burnsides^Aaron^^^||131.001SAV|
BTS|2|
FTS|1|
Credit Message:
FHS|^~\&|CVIS|CVIS|SAV|SAV|20130130091006|
BHS|^~\&|CVIS|CVIS|SAV|SAV|20130130091006||20130130|
MSH|^~\&|CVIS|CVIS|SAV|SAV|20130130091006||DFT^P03|2013013009100605924|P|2.3|||AL|||Windows-1252|
EVN|P03|20130130091006|
PID|||H0000283||BAR^CATHTEST1^^^||19800113|M||U|^^SALINAS^CA^93901^|||||||H00000605|||||
PV1||O|^^^||||||||||||||||H00000605|||||||||||||||||||||||||20130114093900|
FT1||||20130114|20130130091006|CD|24100039^PACEMAKER GENERATOR INSERTION W/ EXISTING DUAL LEADS|PACEMAKER GENERATOR INSERTION W/ EXISTING DUAL LEADS||1|||CAR|||^^^|||||ABURNSID^Burnsides^Aaron^^^||130.001SAV|
FT1||||20130114|20130130091006|CD|24700002^EP CATHETER DUO DEC LIVEWIRE 7FR |EP CATHETER DUO DEC LIVEWIRE 7FR ||1|||CAR|||^^^|||||ABURNSID^Burnsides^Aaron^^^||130.001SAV|
MSH|^~\&|CVIS|CVIS|SAV|SAV|20130130091006||DFT^P03|2013013009100623111|P|2.3|||AL|||Windows-1252|
EVN|P03|20130130091006|
PID|||H0000284||BAR^CATHTEST2^^^||19820101|M||U|^^SALINAS^CA^93939^|||||||H00000606|||||
PV1||O|^^^||||||||||||||||H00000606|||||||||||||||||||||||||20130114094000|
FT1||||20130114|20130130091006|CD|24100003^COMPREHENSIVE EP EVALUATION W/LV PACING \T\ RECORDING (VT BASELINE + LV)|COMPREHENSIVE EP EVALUATION W/LV PACING \T\ RECORDING (VT BASELINE + LV)||1|||CAR|||^^^|||||ABURNSID^Burnsides^Aaron^^^||131.001SAV|
FT1||||20130114|20130130091006|CD|22000402^BALLOON ANGIOSCULPT|BALLOON ANGIOSCULPT||1|||CAR|||^^^|||||ABURNSID^Burnsides^Aaron^^^||131.001SAV|
BTS|2|
FTS|1|** All programmers are playwrights, and all computers are lousy actors.
-
Ok, with some further testing the timing issue certainly has something to do with it. When I ran the program in debug mode with no breaks, the same behavior showed up. It seems that when the program breaks it slows everything down so that the message comes through. However in compiled mode it runs at full speed. Is there anyway to loop until the message has been recevied totally? It seems that the stream.DataAvailable is unreliable.
ie.
Do until stream.DoneReading = True
thread.sleep(10)
Loop
I'm playing around with putting sleep commands around when the client connects and the stream is read....
** All programmers are playwrights, and all computers are lousy actors.
-
the way you read, you read once and then continue
if you starve the buffer because you are reading faster than the data is coming, you will stop to read even if dataAvailable is true
May be should you read in a loop
do
Stream.read( ... )
loop while stream.DataAvailableand use a string builder to store the data as it comes
- Edited by Crazypennie Friday, February 1, 2013 6:03 PM
-
I just dropped in a sleep after the client connects to allow the stream to fill up.... from what I can tell this seems to have solved the issue. I'm still going to do some more extensive testing, but for now the messages appear to be coming through. Turns out that the CVIS vendor indicated that he noticed when sending the charge messages they go out right away, but that the credit messages hang in a 'processing' state for a little bit before going. I think their interface was connecting, and starting to send the message while it's still being processed on their side adding a few millisecond delay to those messages.
** All programmers are playwrights, and all computers are lousy actors.
-
Well I've found out one thing, when I send charges from my TCP Transmitter to your application, your application always receives the data and then transmits the data to my TCP Receiver. I can do this continually over and over.
When I send Credits from my TCP Transmitter to your application, your application apparently receives the data (since the receive textbox data increases in length). But when your application retransmits the data to my TCP Listener then my TCP Listener continually locks up and doesn't receive the data. And that is not in Debug mode.
Unfortunately everything is looping within my IP stack and never gets to the level in the IP stack I need it to get to in order to monitor the data with my Wireshark protocol analyzer.
Debugging continues.......
On another note I just found out that when I send Credits directly to my TCP Listener from my TCP Transmitter everything is fine.
I will add your system.threading.thread.sleep into the mix and see what occurs.
You've taught me everything I know but not everything you know.
- Edited by Mr. Monkeyboy Friday, February 1, 2013 7:23 PM
-
-
Fantastic! That did it.... I just had to slow down the compiled program enough to wait for the stream buffer to fill up with the message that the CVIS system was sending. Maybe it's painful for the system to generate credits LOL!
Thank you for your help and attention to my post, I appreciate it!
** All programmers are playwrights, and all computers are lousy actors.
-
I just dropped in a sleep after the client connects to allow the stream to fill up.... from what I can tell this seems to have solved the issue. I'm still going to do some more extensive testing, but for now the messages appear to be coming through. Turns out that the CVIS vendor indicated that he noticed when sending the charge messages they go out right away, but that the credit messages hang in a 'processing' state for a little bit before going. I think their interface was connecting, and starting to send the message while it's still being processed on their side adding a few millisecond delay to those messages.
** All programmers are playwrights, and all computers are lousy actors.
Well hopefully that resolves the issue though I would hate to rely on a timer like that in the process since it seems "out of place" used in that way for two reasons. First it halts the thread for the specified time period which is bad and second it may not incorporate a long enough time in it for some instances. I would think that there could be an if data present then type of scenario used to resolve this or a while data is not present loop type of scenarion. After all network data goes out in a framed format over the hardware layers so it's possible to have a busy network and the time extend past 100 miliseconds on the hardware layer alone I would guess but I may be way off on that estimate since I just pinged google and it took only 75 to 80 milliseconds including the round trip delay.
But I still despise that thread sleep timer. :(
You've taught me everything I know but not everything you know.
- Proposed as answer by Mr. Monkeyboy Friday, February 1, 2013 9:24 PM
- Marked as answer by Youen ZenModerator Monday, February 11, 2013 8:28 AM
-
Agreed. Maybe I'll try what Crazypennie suggested and loop until the stream is empty. I thought that I had tried that once and found the DataAvailable to not be consistent. Could be wrong though... wouldn't be the first time (or last time LOL!).
** All programmers are playwrights, and all computers are lousy actors.
- Proposed as answer by Mr. Monkeyboy Friday, February 1, 2013 9:24 PM
- Marked as answer by Youen ZenModerator Monday, February 11, 2013 8:28 AM
- Unmarked as answer by Timothy B. France Monday, February 11, 2013 4:06 PM
-
Hi,
Just as a follow-up. I tried several variations of a loop that would wait for the buffer to fill, but was unable to comensate for the time lag from the server. Finally, although seemingly just a bandaid, I added the sleep(500) funtion after the tcp connection is accepted, and another sleep(500) after the read stream command. We have ran through many different (and some lengthy) messages through and they are processing just fine now. Not sure how other established interface engines handle this, but this 'fix' worked :)
Thanks again for the assist,
Tim
** All programmers are playwrights, and all computers are lousy actors.
-
-
Hi,
I thought I did, but after looking at your code I realized that I didn't have the boolean in the loop... it was in the for instead.... I'll go back and try in the proposed way :)
Thanks,
Tim
** All programmers are playwrights, and all computers are lousy actors.