PDA

View Full Version : String Manipulation and Networking Questions.



Voltrox
06-09-2006, 02:25 PM
Hello,

I created a client and server Application in Delphi and am having a very serious problem.

The client is sending a message to the server every 1 millisecond to see how the server performs and my server is supposed to respond with 'Response: Server recieved text.', and it does most of the time but sometimes it sends 'Response: Server recieved text.Response: Server recieved text.' in one line, which it shouldn't.

Also, how do I read all the rest of the characters in a string EXCEPT the first 4 that are in the string?

The application itself is about 600KB in size. But it is using 60 MB of memory.

How can I make it free memory?

Could someone please help me?

Thank you.

TheDon
07-09-2006, 01:17 PM
Hello!

Do you wait for the response from the server before you send him another package from the client?

TCP Connections must be used like byte oriented streams and not packed oriented streams, because the IP packages can be fragmented from one host to another or are put together on the receivers side, if the receiver is too busy to handle each packet.

That's the reason, why you get multiple messages in "one read".

If client/server receives a message you have to do something like this


while DataAvailable do
ReadOneMessage


For the "ReadOneMessage" part you have to introduce some sort of internal packaging, like adding a special character at the of each messages (CR?) or start with a message len.

Why do you want to dismiss the first 4 characters? Are they looking ugly? Then it may be the length (in Bytes) of the received message. Read the first 4 bytes as an 32bit Integer and then exactly the amount of characters for the message-data.

For further help, simply post your code
HTH

Voltrox
07-09-2006, 03:01 PM
Hi :)

Yes....

"
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, XPMan, ScktComp, ExtCtrls;

type
TForm1 = class(TForm)
CSOCK1: TClientSocket;
XPManifest1: TXPManifest;
Button1: TButton;
MTXB1: TMemo;
TXTS1: TMemo;
Button2: TButton;
SVATT1: TTimer;
LBMSCOUNT2: TLabel;
procedure SVATT1Timer(Sender: TObject);
procedure CSOCK1Disconnect(Sender: TObject; Socket: TCustomWinSocket);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure CSOCK1Read(Sender: TObject; Socket: TCustomWinSocket);
procedure CSOCK1Connect(Sender: TObject; Socket: TCustomWinSocket);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
MSCOUNT2: integer;
VSOCKR2: string;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
CSOCK1.Active := true;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
CSOCK1.Socket.SendText(TXTS1.Text);
TXTS1.Lines.Clear;
end;

procedure TForm1.CSOCK1Connect(Sender: TObject; Socket: TCustomWinSocket);
begin
MTXB1.Lines.Add('Connected to server');
Socket.SendText('Client-Server connection successful');
end;

procedure TForm1.CSOCK1Disconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
Windows.Beep(400, 100);
MTXB1.Lines.Add('Disconnected');
end;

procedure TForm1.CSOCK1Read(Sender: TObject; Socket: TCustomWinSocket);
begin
VSOCKR2 := Socket.ReceiveText;
if VSOCKR2 <> 'Response: Server recieved text.' then MTXB1.Lines.Add(VSOCKR2);
if VSOCKR2 = 'Response: Server recieved text.' then
begin
MSCOUNT2 := MSCOUNT2 + 1;
LBMSCOUNT2.Caption := IntToStr(MSCOUNT2);
end;
if VSOCKR2 = 'PING' then Socket.SendText(VSOCKR2);

end;

procedure TForm1.SVATT1Timer(Sender: TObject);
begin
if VSOCKR2 = 'Response: Server recieved text.' then
begin
if CSOCK1.Socket.Connected = true then CSOCK1.Socket.SendText('Testing server...');
end;

end;

end."

That's the modified code,, so now it still sends two on the same line. :(

It stops.

How can I fix that?

Sloppy, I know. :(

Disregard the unessecary parts like the PING part, which is a mistake.

The client sends a message, and then the server replies to each message with "Response: Server recieved text.". Then it goes on like that.

But the problem, is that sometimes when it's going really fast I see "Response: Server recieved text.Response: Server recieved text."

What do I do?

I understand what you're saying;

TheDon
07-09-2006, 06:06 PM
Hello again!



procedure TForm1.CSOCK1Read&#40;Sender&#58; TObject; Socket&#58;TCustomWinSocket&#41;;
begin
VSOCKR2 &#58;= Socket.ReceiveText;
if VSOCKR2 <> 'Response&#58; Server recieved text.' then MTXB1.Lines.Add&#40;VSOCKR2&#41;;
if VSOCKR2 = 'Response&#58; Server recieved text.' then
begin
MSCOUNT2 &#58;= MSCOUNT2 + 1;
LBMSCOUNT2.Caption &#58;= IntToStr&#40;MSCOUNT2&#41;;
end;
end;

procedure TForm1.SVATT1Timer&#40;Sender&#58; TObject&#41;;
begin
if VSOCKR2 = 'Response&#58; Server recieved text.' then
begin
if CSOCK1.Socket.Connected = true then CSOCK1.Socket.SendText&#40;'Testing server...'&#41;;
end;
end;


The problemtic code is the timer.
If the value in VSOCKR2 is not "Response:..." no new messages are sent to the server. Because no new messages are sent to the server, your app don't receive a response and the value in VSOCKR2 will remain incorret.
Therefore it will stop sending.
On the other side, if the value in VSOCKR2 is correct, you send a message to your server and you don't reset the value to VSOCKR2 to ''. This means that VSOCKR2 is still correct, even if you don't have received any response from the server.

I am going to post my own code example later.

HTH

TheDon
07-09-2006, 07:40 PM
The project-file:

program Project1;

uses
Forms,
Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.


The Form:

object Form1: TForm1
Left = 221
Top = 134
Width = 747
Height = 485
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 232
Top = 16
Width = 32
Height = 13
Caption = 'Label1'
end
object ClientBtn: TButton
Left = 16
Top = 8
Width = 75
Height = 25
Caption = 'ClientBtn'
TabOrder = 0
OnClick = ClientBtnClick
end
object ClientLog: TListBox
Left = 16
Top = 40
Width = 353
Height = 393
ItemHeight = 13
TabOrder = 1
end
object ServerLog: TListBox
Left = 384
Top = 40
Width = 337
Height = 393
ItemHeight = 13
TabOrder = 2
end
object ServerBtn: TButton
Left = 384
Top = 8
Width = 75
Height = 25
Caption = 'ServerBtn'
TabOrder = 3
OnClick = ServerBtnClick
end
object ClientSocket: TClientSocket
Active = False
ClientType = ctNonBlocking
Host = 'localhost'
Port = 2018
OnLookup = ClientSocketLookup
OnConnecting = ClientSocketConnecting
OnConnect = ClientSocketConnect
OnDisconnect = ClientSocketDisconnect
OnRead = ClientSocketRead
OnWrite = ClientSocketWrite
OnError = ClientSocketError
Left = 104
Top = 8
end
object ServerSocket: TServerSocket
Active = False
Port = 2018
ServerType = stNonBlocking
OnListen = ServerSocketListen
OnAccept = ServerSocketAccept
OnGetThread = ServerSocketGetThread
OnGetSocket = ServerSocketGetSocket
OnThreadStart = ServerSocketThreadStart
OnThreadEnd = ServerSocketThreadEnd
OnClientConnect = ServerSocketClientConnect
OnClientDisconnect = ServerSocketClientDisconnect
OnClientRead = ServerSocketClientRead
OnClientWrite = ServerSocketClientWrite
OnClientError = ServerSocketClientError
Left = 472
Top = 8
end
object ClientTimer: TTimer
Enabled = False
Interval = 1
OnTimer = ClientTimerTimer
Left = 136
Top = 8
end
object Timer1: TTimer
OnTimer = Timer1Timer
Left = 280
Top = 8
end
end



The Unit:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ScktComp, ExtCtrls;

type
TForm1 = class(TForm)
ClientBtn: TButton;
ClientLog: TListBox;
ClientSocket: TClientSocket;
ServerSocket: TServerSocket;
ServerLog: TListBox;
ServerBtn: TButton;
ClientTimer: TTimer;
Label1: TLabel;
Timer1: TTimer;
procedure ClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocketConnecting(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocketError(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedure ClientSocketLookup(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
procedure ClientSocketWrite(Sender: TObject; Socket: TCustomWinSocket);
procedure ClientBtnClick(Sender: TObject);
procedure ServerBtnClick(Sender: TObject);
procedure ServerSocketAccept(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocketClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocketClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocketClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
procedure ServerSocketGetSocket(Sender: TObject; Socket: Integer;
var ClientSocket: TServerClientWinSocket);
procedure ServerSocketGetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
procedure ServerSocketListen(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocketThreadEnd(Sender: TObject;
Thread: TServerClientThread);
procedure ServerSocketThreadStart(Sender: TObject;
Thread: TServerClientThread);
procedure ClientTimerTimer(Sender: TObject);
procedure ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocketClientWrite(Sender: TObject;
Socket: TCustomWinSocket);
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);

{ Private-Deklarationen }
public
{ Public-Deklarationen }
ServerRecvBuf,
ClientRecvBuf : String;
Packets : Integer;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ClientLog.Items.Add('Connect '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort));
end;

procedure TForm1.ClientSocketConnecting(Sender: TObject;
Socket: TCustomWinSocket);
begin
ClientLog.Items.Add('Connecting '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort));
end;

procedure TForm1.ClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ClientLog.Items.Add('Disconnect '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort));
end;

procedure TForm1.ClientSocketError(Sender: TObject;
Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
ClientLog.Items.Add('Error '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort)+' '+
IntToStr(ErrorCode));
end;

procedure TForm1.ClientSocketLookup(Sender: TObject;
Socket: TCustomWinSocket);
begin
ClientLog.Items.Add('LookUp '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort));
end;

procedure TForm1.ClientBtnClick(Sender: TObject);
begin
ClientSocket.Active := not ClientSocket.Active;
ClientTimer.Enabled := not ClientTimer.Enabled;
end;

procedure TForm1.ServerBtnClick(Sender: TObject);
begin
ServerSocket.Active := not ServerSocket.Active;
end;

procedure TForm1.ServerSocketAccept(Sender: TObject;
Socket: TCustomWinSocket);
begin
ServerLog.Items.Add('Accept '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort));
end;

procedure TForm1.ServerSocketClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ServerLog.Items.Add('Connect '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort));

end;

procedure TForm1.ServerSocketClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ServerLog.Items.Add('Disconnect '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort));
end;

procedure TForm1.ServerSocketClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
ServerLog.Items.Add('Error '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort)+' '+
IntToStr(ErrorCode));
end;

procedure TForm1.ServerSocketGetSocket(Sender: TObject; Socket: Integer;
var ClientSocket: TServerClientWinSocket);
begin
if Assigned(ClientSocket) then
ServerLog.Items.Add('GetSocket '+
ClientSocket.RemoteAddress+' '+
IntToStr(ClientSocket.RemotePort))
else
ServerLog.Items.Add('GetSocket');

end;

procedure TForm1.ServerSocketGetThread(Sender: TObject;
ClientSocket: TServerClientWinSocket;
var SocketThread: TServerClientThread);
begin
if Assigned(SocketThread) then
ServerLog.Items.Add('GetThread '+
ClientSocket.RemoteAddress+' '+
IntToStr(ClientSocket.RemotePort)+' '+
IntToStr(SocketThread.Handle))
else
ServerLog.Items.Add('GetThread '+
ClientSocket.RemoteAddress+' '+
IntToStr(ClientSocket.RemotePort));
end;

procedure TForm1.ServerSocketListen(Sender: TObject;
Socket: TCustomWinSocket);
begin
ServerLog.Items.Add('Listen '+
Socket.LocalAddress+' '+
IntToStr(Socket.LocalPort));
end;

procedure TForm1.ServerSocketThreadEnd(Sender: TObject;
Thread: TServerClientThread);
begin
ServerLog.Items.Add('EndThread '+
IntToStr(Thread.Handle));
end;

procedure TForm1.ServerSocketThreadStart(Sender: TObject;
Thread: TServerClientThread);
begin
ServerLog.Items.Add('StartThread '+
IntToStr(Thread.Handle));
end;

//------------------------------------------

procedure TForm1.ClientTimerTimer(Sender: TObject);
begin
//Send the message. Use the #13 (CR) as Message separator
ClientSocket.Socket.SendText('MyText'#13);
end;

procedure TForm1.ClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
var
Data : String;
iPos : Integer;
//iCount : Integer;
begin
//Receive the whole buffer
ClientRecvBuf := ClientRecvBuf + Socket.ReceiveText;

//Read messages till buffer is empty
//iCount:=1;
repeat
iPos := 1;
while iPos<length(ClientRecvBuf) do
begin
//Check for seperator char
if ClientRecvBuf[iPos]=#13 then break;
inc(iPos);
end;

Data := Copy(ClientRecvBuf,1,iPos-1);
Delete(ClientRecvBuf,1,iPos);
{
ClientLog.Items.Add('Read '+IntToStr(iCount)+' '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort)+' '+
Data);
inc(iCount);
}
inc(Packets);

until ClientRecvBuf='';
end;

procedure TForm1.ClientSocketWrite(Sender: TObject;
Socket: TCustomWinSocket);
begin
{
ClientLog.Items.Add('Write '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort));
}
end;

procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
Data : String;
iPos : Integer;
begin
//Receive the whole buffer
ServerRecvBuf := ServerRecvBuf + Socket.ReceiveText;

//Read messages till buffer is empty
repeat
iPos := 1;
while iPos<length(ServerRecvBuf) do
begin
//Check for seperator char
if ServerRecvBuf[iPos]=#13 then break;
inc(iPos);
end;

//Only process data, if Message is complete (last char =#13)
//This is alway true, as long as iPos is not byond the end
//of the Buffer
if iPos<=length(ServerRecvBuf) then
begin
Data := Copy(ServerRecvBuf,1,iPos-1);
Delete(ServerRecvBuf,1,iPos);
{
ServerLog.Items.Add('Read '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort)+' '+
Data);
}

//Just for randomly generate multiple receives.
If Random(100)=5
then Socket.SendText('ReceivedText'#13'ReceivedText'#13 )
else Socket.SendText('ReceivedText'#13);
end;

until ClientRecvBuf='';

end;

procedure TForm1.ServerSocketClientWrite(Sender: TObject;
Socket: TCustomWinSocket);
begin
ServerLog.Items.Add('Write '+
Socket.RemoteAddress+' '+
IntToStr(Socket.RemotePort));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Randomize;
Packets := 0;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
Label1.Caption := IntToStr(Packets);
end;

end.

Voltrox
07-09-2006, 10:42 PM
The problem is that I don't want it to halt everything when there's an error, but I don't want it to generate that error in the first place...because if I just told it to stop, then i would end up losing thousands of messges and that would be really bad....

thanks.

TheDon
07-09-2006, 11:40 PM
What kind of error do you mean? From your app or from my testapp?

Sly
07-09-2006, 11:55 PM
You are using TCP for your connection. TCP can concatenate packets into one larger packet, so your code must be able to handle this. Usually this is done by inserting your own separators or a small header that tells the receiver the length of the packet. The receiver then reads the header or looks for the separators to be able to split the packets up into their original form.

Having said that, commercial games use UDP for their networking because it does not suffer the overhead that TCP adds to a connection (ACKs, resends, etc).

Voltrox
08-09-2006, 12:30 AM
from my app :(

the error is the repeating of that packet.

TheDon
08-09-2006, 01:00 AM
My Testapp should give you an idea how to solve your problem. In my test-app I have implemented both, client AND server in one app. I also have added a lot of unnecessary eventhandlers for the client and the serversocket, which you do not need.

In both cases the Read-Event should be enought + the timer to send messages to the server.

Look especially to
ClientSocketRead
ServerSocketClientRead

You can see, that I have added the #13 as the message-seperator. Don't bother with the Random(100)=5. This is for simply generate your behaviour and test the reaction of the client.

Clootie
08-09-2006, 08:30 AM
Having said that, commercial games use UDP for their networking because it does not suffer the overhead that TCP adds to a connection (ACKs, resends, etc).
While this is 99% true - there are always exceptions of supposedly good rule. In this case it's the "World of Warcraft". Yep, it's not an action game, but anyway...

Voltrox
14-09-2006, 03:44 AM
thanks :(

i still haven't gotten past the problem :(

TheDon
14-09-2006, 04:16 PM
What have you changed in your source to try to solve the problem? If both Apps (Client and Server) are small, you can send me the sources via private mail. Without an up to date source-code it is difficult to give advices.

Other possibilities are using UDP and/or using the Indy components.

bye

Voltrox
16-09-2006, 02:53 AM
I'm using the Tclientsocket and Tserversocket components for this.

Is TServerSocket and TClientSocket UDP or TCP or what?

It seemed very different like it would be very confusing to change all of that, i'll try it. :(

do you happen to have an instant messenger TheDon?

Could someone show me or directly accordingly as to how I can use the TTcpClient and TTcpServer components?

I really need to learn them and have had no luck in figuring out how to learn them :(

Thank you.

TheDon
16-09-2006, 01:52 PM
Instant messaging may be a problem because of the big time difference between Jamaica and Austria. I am at GMT+1/+2.

Which Pascal compiler do you use (I am using Delphi 7 Pro)? The TServerSocket and TClientSocket use TCP as transport protocol. Do you need additional features in your Client/Server or only "still alive" and status messages? If the later is true, I would suggest to use UDP, preferable the Indy UDP components, because they are very easy to use.

I don't use TTCPClient and TTCPServer and therefore I do not know the differences to TServerSocket and TClientSocket.

In your first source-code example you are using the TClientSocket with the Read event.


procedure TForm1.CSOCK1Read&#40;Sender&#58; TObject; Socket&#58; TCustomWinSocket&#41;;

var
i &#58; integer;
AMessage &#58; string;
MoreMessage &#58; Boolean;

begin
// If a message &#40;one Socket.SendText&#40;&#41; was split into multiple parts, you need more
// than one read event, to process messages
// VSOCKR2 must be "global", you may define it in TForm1 &#40;private&#41;
// instead of &#58; VSOCKR2 &#58;= Socket.ReceiveText;
VSOCKR2 &#58;= VSOCKR2 + Socket.ReceiveText;

//Because it is possible to receive more than one message
//in one Read event all data in the VSOCKR2 must be parsed
//Therefore it is important to define a message-structure
//We define it this way&#58; CR is our message seperator
// <AnyTextWithoutTheCRChar>+CR &#40;CR = #13&#41;
//Because of our definition, it is not allowed to send messages
//with a CR &#40;Carriage Return&#41; in the message text itself
repeat
MoreMessages &#58;= false

//Search for the first message seperator
for i &#58;=1 to length&#40;VSOCKR2&#41; do
begin
//message seperator at position i?
if VSOCKR2&#91;i&#93;=#13 then
begin
//Copy the message from the buffer
AMessage &#58;= Copy&#40;VSOCKR2,1,i-1&#41;;
//Delete the message from the buffer, including the CR
Delete&#40;VSOCKR2,1,i&#41;;
//reenable timer to send a new request to the server
SVATT1.Enabled &#58;= true;

//if there is still some data in the VSOCKR2 buffer
//we have to check for another message
if VSOCKR2<>'' then
MoreMessages&#58;=true;

//Perform some work with AMessage like&#58;
if AMessage = 'Response&#58; Server received text.' then
begin
MSCOUNT2 &#58;= MSCOUNT2 + 1;
LBMSCOUNT2.Caption &#58;= IntToStr&#40;MSCOUNT2&#41;;
end;
//onPing return the PING to the sender. We must not
//forget the CR as the message seperator
if AMessage = 'PING' then Socket.SendText&#40;AMessage+#13&#41;;

end;
end;

until not MoreMessages;

end;

//The Timer
procedure TForm1.SVATT1Timer&#40;Sender&#58; TObject&#41;;
begin
//Send request to server with the message-seperator
if CSOCK1.Socket.Connected = true then
CSOCK1.Socket.SendText&#40;'Testing server...'+#13&#41;;

//disable Timer
SVATT1.Enabled&#58;=false;
end;


The changes in the Client's read event apply also to the Server's read event and all Servers "Socket.SendText()" must be completed with the CR message seperator.

I can also provide an example of using the indy UDP components, if you want.

HTH

Voltrox
17-09-2006, 03:43 PM
Thank you. :)

It's ok, I couldn't waste any more of your time, and that #13 CR should be helpful.

But now my server can't send messages directly to the client unless it's in an onrecieve or onconnect event, it said address not supplied, could someone tell me what to do?

Thank you. :)

TheDon
17-09-2006, 10:09 PM
Working and solving problems is never a waste of time and it does not matter, if it is your own problem or the problem of someone else.

I will try to reproduce the problem and answer the question in your other post about this problem.

Voltrox
18-09-2006, 09:03 PM
Oh, thank you. :)