Trying to understood how to use ServerSocket and ClientSocket in Delphi. I made a simple chat programm but after client sends first message this error apperas
(it happens during sending - just after server get's the message )
Windows socket error: Запрос на отправку или получение данных (when sending ona datagram socket using a sendto call)no adress was supplied (10057), on API 'getpeername'
Heres server code
unit Servert;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ScktComp;
type
TForm1 = class(TForm)
ServerSocket: TServerSocket;
PortLabel: TLabel;
Port: TEdit;
Protocol: TGroupBox;
mmoServer: TMemo;
btnStart: TButton;
btnStop: TButton;
btnClear: TButton;
btnEnd: TButton;
btnSend: TButton;
edtMsg: TEdit;
lblUser: TLabel;
procedure btnStartClick(Sender: TObject);
procedure btnStopClick(Sender: TObject);
procedure btnClearClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btnEndClick(Sender: TObject);
procedure ServerSocketClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocketClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocketClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
procedure ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure btnSendClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Usercount: Integer;
implementation
{$R *.dfm}
procedure TForm1.btnStartClick(Sender: TObject);
begin
ServerSocket.Port:=StrToInt(Port.Text);
ServerSocket.Active:=True;
btnStart.Enabled:=False;
btnStop.Enabled:=True;
mmoServer.Lines.Add('Status: started');
end;
procedure TForm1.btnStopClick(Sender: TObject);
begin
ServerSocket.Port:=StrToInt(Port.Text);
ServerSocket.Active:=False;
btnStart.Enabled:=True;
btnStop.Enabled:=False;
mmoServer.Lines.Add('Status: stopped');
end;
procedure TForm1.btnClearClick(Sender: TObject);
begin
mmoServer.Lines.Clear;
mmoServer.Lines.Add('Server 1.0');
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
ServerSocket.Active:=False;
end;
procedure TForm1.btnEndClick(Sender: TObject);
begin
ServerSocket.Active:=False;
Application.Terminate;
end;
procedure TForm1.ServerSocketClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
mmoServer.Lines.Add('Status: Client ' + Socket.RemoteAddress + ' connected');
Inc(Usercount);
lblUser.Caption:= 'User:' + IntToStr(Usercount);
end;
procedure TForm1.ServerSocketClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
mmoServer.Lines.Add('Status: Client ' + Socket.RemoteAddress + ' disconnected');
Dec(Usercount);
lblUser.Caption:= 'User:' + IntToStr(Usercount);
end;
procedure TForm1.ServerSocketClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
mmoServer.Lines.Add('Status: Client ' + Socket.RemoteAddress + ' error:' + IntToStr(ErrorCode));
Dec(Usercount);
lblUser.Caption:= 'User:' + IntToStr(Usercount);
end;
procedure TForm1.ServerSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var i:Integer; strRec:AnsiString;
begin
strRec:=Socket.RemoteAddress + ': ' + Socket.ReceiveText;
mmoServer.Lines.Add(strRec);
for i:=0 to ServerSocket.Socket.ActiveConnections - 1 do begin
ServerSocket.Socket.Connections[i].SendText(strRec);
end;
end;
procedure TForm1.btnSendClick(Sender: TObject);
var i:Integer;
begin
for i:=0 to ServerSocket.Socket.ActiveConnections - 1 do
begin
ServerSocket.Socket.Connections[i].SendText('Ololo' + edtMsg.Text);
mmoServer.Lines.Add('Ololo' + edtMsg.Text);
end;
end;
end.
Here's client code
unit Client;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ScktComp, StdCtrls;
type
TForm1 = class(TForm)
lblHost: TLabel;
edtHost: TEdit;
lblPort: TLabel;
edtPort: TEdit;
btnConnect: TButton;
btnDisconnect: TButton;
grp1: TGroupBox;
mmoClient: TMemo;
grpSend: TGroupBox;
mmoSend: TMemo;
btnSend: TButton;
ClientSocket: TClientSocket;
procedure ClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure btnDisconnectClick(Sender: TObject);
procedure btnConnectClick(Sender: TObject);
procedure ClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
procedure btnSendClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ClientSocketConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
mmoClient.Lines.Add('Status: connected ' + Socket.RemoteAddress);
end;
procedure TForm1.btnDisconnectClick(Sender: TObject);
begin
ClientSocket.Host:=edtHost.Text;
ClientSocket.Port:=StrToInt(edtPort.Text);
ClientSocket.Active:=False;
btnConnect.Enabled:=True;
btnDisconnect.Enabled:=False;
end;
procedure TForm1.btnConnectClick(Sender: TObject);
begin
ClientSocket.Host:=edtHost.Text;
ClientSocket.Port:=StrToInt(edtPort.Text);
ClientSocket.Active:=True;
btnConnect.Enabled:=False;
btnDisconnect.Enabled:=True;
end;
procedure TForm1.ClientSocketDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
mmoClient.Lines.Add('Status: disconnected ' + Socket.RemoteAddress)
end;
procedure TForm1.ClientSocketRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
mmoClient.Lines.Add(Socket.ReceiveText);
end;
procedure TForm1.btnSendClick(Sender: TObject);
begin
ClientSocket.Socket.SendText(mmoSend.Text);
end;
end
.
i'm really sorry if i'm posting this late, but i solved this issue and you might not see it.
in the server-side, make sure that you send to the socket by index, example:
ServerSocket1.Socket.Connections[SocketIndex].SendText();
Don't forget the .Connections property.
Error code 10057 is WSAENOTCONN, and getpeername() is the API function that the Socket.RemoteAddress property getter uses internally. This means you tried to read the RemoteAddress property of a Socket that was no longer connected to the server.
Related
provide an example in DELPHI 5 if is possible
lets say we have the follow code.A simple tclientsocket communicates with a tserver socket.
Everything works fine if requests from tclientsocket are coming after the process of data on event tserversocket1onReadClient.
But How i will bypass the problem when on the middle of process i am getting a new Request from socketclient1 and i havent finish yet my process?
do i have to Implement it in ServerType: stThreadBlocking
Do i have to Create a thread to Do the process?
is it a better way do this simple.
My tclientsocket string messages will not be larger than 255 chars.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ScktComp;
type
TForm1 = class(TForm)
ClientSocket1: TClientSocket;
Button1: TButton;
ServerSocket1: TServerSocket;
procedure Button1Click(Sender: TObject);
procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedure ServerSocket1ClientError(Sender: TObject;Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;var ErrorCode: Integer);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
private
public
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
with Serversocket1 do
begin
Active:=false;
ServerType:=stNonBlocking;
port:=5052;
Active:=true;
end;
with ClientSocket1 do
begin
active:=false;
port:=5052;
Address:='127.0.0.1';
host:='127.0.0.1';
active:=true;
end;
end;
procedure TForm1.ClientSocket1Error(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
errorcode:=0;
end;
procedure TForm1.ServerSocket1ClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
errorcode:=0;
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;Socket: TCustomWinSocket);
var mydata:String;
begin
mydata:=socket.ReceiveText;
///Proceccing my data now
//Line 1
//Line 2
//Line 3
//Line 4 <---- ie. when i am proccessing line 4 a new Request from clientsocket1 arrives
//Line 5
end;
end.
The scenario you describe cannot happen. When the ServerSocket1ClientRead event handler is executing, it will not be called in a re-entrant fashion. Well, unless you were to call Application.ProcessMessages. So, don't do that!
I have just started working with Threads use the onexecute event with Delphi 2009, indy IdTCPServer1. I wrote a very basic application for testing and am getting an access violation on exit. The application runs fine and does everything I want it to, but I think that I am leaving "Threads running" on exit. I have no experience with threads so any help would be appreciated.
Heres my code
unit FT_Communicator_pas;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ScktComp, IdContext, IdTCPServer,
INIFiles, ExtCtrls, ComCtrls, adscnnct,
DB, adsdata, adsfunc, adstable, Wwdatsrc, Grids, Wwdbigrd, Wwdbgrid,
IdBaseComponent, IdComponent, IdCustomTCPServer;
type
TfrmMain = class(TForm)
IdTCPServer1: TIdTCPServer;
PgMain: TPageControl;
TsMain: TTabSheet;
tsConfig: TTabSheet;
Label1: TLabel;
Label2: TLabel;
txtServer: TEdit;
txtPort: TEdit;
Panel1: TPanel;
Panel3: TPanel;
tsLog: TTabSheet;
mnolog: TMemo;
Button1: TButton;
Button3: TButton;
procedure IdTCPServer1Connect(AContext: TIdContext);
procedure IdTCPServer1Execute(AContext: TIdContext);
procedure Button3Click(Sender: TObject);
procedure IdTCPServer1Disconnect(AContext: TIdContext);
procedure Logit(const Logstr: String);
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmMain: TfrmMain;
implementation
{$R *.dfm}
procedure TfrmMain.Button1Click(Sender: TObject);
begin
IdTCPServer1.Active:=FALSE;
application.Terminate;
end;
procedure TfrmMain.Button3Click(Sender: TObject);
begin
IdTCPServer1.Active:=true;
end;
procedure TfrmMain.FormShow(Sender: TObject);
begin
PgMain.ActivePage:=tsMain;
EnableMenuItem( GetSystemMenu( handle, False ),SC_CLOSE, MF_BYCOMMAND or MF_GRAYED );
end;
procedure TfrmMain.IdTCPServer1Connect(AContext: TIdContext);
begin
mnoLog.lines.Add ('Connected from: ' + AContext.Connection.Socket.Binding.PeerIP);
end;
procedure TfrmMain.IdTCPServer1Disconnect(AContext: TIdContext);
begin
mnoLog.lines.Add ('Disconnected from: ' + AContext.Connection.Socket.Binding.PeerIP);
end;
procedure TfrmMain.IdTCPServer1Execute(AContext: TIdContext);
var
myReadln,mySendln,sqlqry:string;
begin
sleep(10);
myReadln:=AContext.Connection.IOHandler.ReadLn();
mnolog.Lines.Add(AContext.Connection.Socket.Binding.PeerIP + '>' + myReadln );
mySendln:= AContext.Connection.Socket.Binding.PeerIP + ' Sent me ' + myReadln;
AContext.Connection.IOHandler.WriteLn(mySendln);
try
except
on E:Exception do
begin
logit('Error occured During execute function ' + #13#10 + e.message);
end;
end;
end;
procedure TfrmMain.logit(const logstr:String);
var
curdate,Curtime:string;
StrGUID:string;
begin
StrGUID:=FormatDateTime('YYYYMMDDHHnnsszzz', Now())+'_ ';
mnolog.lines.add(StrGUID +logstr );
end;
end.
Your TIdTCPServer event handlers contain unsafe code in them.
TIdTCPServer is a multithreaded component, its events are triggered in the context of worker threads. But you are directly accessing a VCL UI control (mnoLog) without synchronizing with the main UI thread. Bad things happen when you do not synchronize, as the VCL is not thread-safe. You must synchronize properly when accessing the UI from a worker thread.
It is also important to avoid performing a synchronous synchronization when deactivating TIdTCPServer from the main UI thread, as that will cause a deadlock. Use an asynchronous synchronization instead.
Try something more like the following:
procedure TfrmMain.IdTCPServer1Connect(AContext: TIdContext);
begin
Logit('Connected from: ' + AContext.Connection.Socket.Binding.PeerIP);
end;
procedure TfrmMain.IdTCPServer1Disconnect(AContext: TIdContext);
begin
Logit('Disconnected from: ' + AContext.Connection.Socket.Binding.PeerIP);
end;
procedure TfrmMain.IdTCPServer1Execute(AContext: TIdContext);
var
myReadln, mySendln, peerIP: string;
begin
myReadln := AContext.Connection.IOHandler.ReadLn();
peerIP := AContext.Connection.Socket.Binding.PeerIP;
Logit(peerIP + '>' + myReadln);
mySendln := peerIP + ' Sent me ' + myReadln;
AContext.Connection.IOHandler.WriteLn(mySendln);
end;
procedure TfrmMain.IdTCPServer1Exception(AContext: TIdContext; AException: Exception);
begin
if not (AException is EIdConnClosedGracefully) then
Logit('Error occured. ' + AException.Message);
end;
procedure TfrmMain.Logit(const Logstr: String);
var
Str: string;
begin
Str := Trim(Logstr);
TThread.Queue(nil,
procedure
begin
mnolog.Lines.Add(FormatDateTime('YYYYMMDDHHnnsszzz', Now()) + ': ' + Str);
end
);
end;
Hi I'm studying sockets on how to send and receive files, I'm using the component ServerSocket1 to do this I have the following code I found searching google.
the client
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
ClientSocket1: TClientSocket;
OpenDialog1: TOpenDialog;
procedure Button1Click(Sender: TObject);
procedure ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent; var ErrorCode: Integer);
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
private
{ Private declarations }
Stream: TMemoryStream;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
ClientSocket1.Address:= '127.0.0.1';
ClientSocket1.Port:= 2500;
ClientSocket1.Open;
end;
procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ShowMessage('Connected.. Now go load a file!');
end;
procedure TForm1.ClientSocket1Error(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
ShowMessage('Did you startup the server? I cannot find it!');
end;
procedure TForm1.Button2Click(Sender: TObject);
var
Size: Integer;
begin
if OpenDialog1.Execute Then
begin
Stream.LoadFromFile(OpenDialog1.Filename);
Size:= Stream.Size;
ClientSocket1.Socket.SendBuf(Size,SizeOf(Size));
ClientSocket1.Socket.SendStream(Stream);
End;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Stream:= TMemoryStream.Create;
end;
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var
S: String;
begin
S:= Socket.ReceiveText;
Socket.Close;
ShowMessage('Client: '+S);
end;
end.
the server
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ScktComp;
type
TForm1 = class(TForm)
ServerSocket1: TServerSocket;
SaveDialog1: TSaveDialog;
procedure FormCreate(Sender: TObject);
procedure ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1Listen(Sender: TObject;
Socket: TCustomWinSocket);
procedure ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
private
{ Private declarations }
Stream: TMemoryStream;
FSize: Integer;
writing: Boolean;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
ServerSocket1.Port:= 2500;
ServerSocket1.Active:= True;
Stream:= TMemoryStream.Create;
writing:= False;
end;
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
ShowMessage('A client has connected');
end;
procedure TForm1.ServerSocket1Listen(Sender: TObject;
Socket: TCustomWinSocket);
begin
ShowMessage('I''m listening');
end;
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
BytesReceived: Longint;
CopyBuffer: Pointer; { buffer for copying }
ChunkSize: Integer;
TempSize: Integer;
const
MaxChunkSize: Longint = 8192; { copy in 8K chunks }
begin
If FSize=0 then
begin
If Socket.ReceiveLength>SizeOf(TempSize) then
begin
Socket.ReceiveBuf(TempSize,SizeOf(TempSize));
Stream.SetSize(TempSize);
FSize:= TempSize //Threadsafe code!
End;
End;
If (FSize>0) and not(writing) then
begin
GetMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
writing:= True;
While Socket.ReceiveLength>0 do
Begin
ChunkSize:= Socket.ReceiveLength;
If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
BytesReceived:= Socket.ReceiveBuf(CopyBuffer^,ChunkSize);
Stream.Write(CopyBuffer^, BytesReceived); { ...write chunk }
Dec(FSize,BytesReceived);
End;
If FSize=0 then
If SaveDialog1.Execute then
begin
If FileExists(SaveDialog1.Filename) then
DeleteFile(SaveDialog1.Filename);
Stream.SaveToFile(SaveDialog1.Filename);
Socket.SendText('File received!');
Stream.SetSize(0);
FSize:= 0;
End;
FreeMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
Writing:= False;
End;
end;
end.
The problem in this code that eh had is that I can only send one I can send a file because when I try to re-send other file errors throws me as 'Access violation at address' or 'Stream read error'.
that I can do to fix this code and you can send multiple files after each?
there is a reference of how to do it with indy sockets?
This is because memorystream used to open the file is not free. You have to free the stream variable before loading the next file to be sent.
I modified your code a bit and it is now working perfectly, I request various files and is ok.
the server
procedure TForm1.ServerClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
BytesReceived: Longint;
CopyBuffer: Pointer; { buffer for copying }
ChunkSize: Integer;
TempSize: Integer;
FileName: array [0..255] of char;
const
MaxChunkSize: Longint = 8192; { copy in 8K chunks }
begin
If FSize=0 then
begin
If Socket.ReceiveLength>SizeOf(TempSize) then
begin
Socket.ReceiveBuf(TempSize,SizeOf(TempSize));
Socket.ReceiveBuf(FileName, sizeOf(FileName));
Save.FileName:= FileName; //I added
Stream:= TMemoryStream.Create;
Stream.SetSize(TempSize);
FSize:= TempSize; //Threadsafe code!
writing:= True;
End;
End;
If (FSize>0) and (writing) then
{before not(writing) -> because in big files, ServerClientRead is call more than one time and the transfer was stopped after the first call, but now it continues.}
begin
GetMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
While Socket.ReceiveLength>0 do
Begin
ChunkSize:= Socket.ReceiveLength;
If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
BytesReceived:= Socket.ReceiveBuf(CopyBuffer^,ChunkSize);
Stream.Write(CopyBuffer^, BytesReceived); { ...write chunk }
Dec(FSize,BytesReceived);
End;
FreeMem(CopyBuffer, MaxChunkSize); { free allocated buffer, now here }
If FSize
Client button click:
procedure TForm1.Button1Click(Sender: TObject);
var ms: TMemoryStream;
size: Integer;
FileName: array [0..255] of char;
begin
if Open.Execute then
begin
ms:= TMemoryStream.Create;
try
ms.LoadFromFile(open.FileName);
ms.Position:= 0;
Size:= MS.Size;
Client.Socket.SendBuf(Size,SizeOf(Size));
StrPLCopy(FileName, ExtractFileName(Open.FileName), High(FileName));
Client.Socket.SendBuf(FileName, SizeOf(FileName));
client.Socket.SendStream(ms);
except
ms.Free;
end;
end;
end;
my server has a list of 4 TCP connected clients . if list full , next client must reject
//Server side
unit ServerUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdThreadMgr, IdThreadMgrDefault, IdAntiFreezeBase, IdAntiFreeze,
IdUDPBase, IdUDPServer, IdBaseComponent, IdComponent, IdTCPServer,
StdCtrls, ExtCtrls,IdSocketHandle, ComCtrls, IdUDPClient, Grids,
IdTCPConnection, IdTCPClient;
type
TForm1 = class(TForm)
Panel1: TPanel;
Label3: TLabel;
Edit3: TEdit;
Button1: TButton;
IdTCPServer1: TIdTCPServer;
IdUDPServer1: TIdUDPServer;
IdAntiFreeze1: TIdAntiFreeze;
IdThreadMgrDefault1: TIdThreadMgrDefault;
StatusBar1: TStatusBar;
GroupBox2: TGroupBox;
IncomingText: TMemo;
GroupBox1: TGroupBox;
Clients_StringGrid: TStringGrid;
IdTCPClient1: TIdTCPClient;
procedure Button1Click(Sender: TObject);
procedure IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
procedure ADDTCPConn(AThread: TIdPeerThread;i:Integer);
procedure DeleteRow1(VGrid: TStringGrid; VRow: integer);
procedure InsertRow1(VGrid: TStringGrid; Str1:String; Str2:String; Str3:String);
Procedure Add_To_StringGrid(Grid:TStringGrid; Str1:String; Str2:String; Str3:String; i:Integer);
procedure FormCreate(Sender: TObject);
procedure IdTCPServer1Execute(AThread: TIdPeerThread);
procedure IdTCPServer1Connect(AThread: TIdPeerThread);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
RCount:Integer;
flag:Boolean;
IPList : TStringList;
IPList2 : TStringList;
fl: Boolean;
implementation
uses CommonUnit;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
if not IdUDPServer1.Active then
begin
IdUDPServer1.DefaultPort:=1717;
IdUDPServer1.BroadcastEnabled:=True;
IdUDPServer1.Active:=True;
end;
if not IdTCPServer1.Active then
begin
IdTCPServer1.DefaultPort:=1717;
IdTCPServer1.Active:=True;
end;
end;
procedure TForm1.IdUDPServer1UDPRead(Sender: TObject; AData: TStream;
ABinding: TIdSocketHandle);
var
s : String;
ip : String;
dss : TStringStream;
begin
try
dss := TStringStream.Create('');
dss.CopyFrom(AData, AData.Size);
s := dss.DataString;
ip:=GetIPAddress();
IncomingText.Lines.Add('Client Say('+ABinding.PeerIP+'):'+s);
IncomingText.Lines.Add('------------');
ABinding.SendTo(ABinding.PeerIP, ABinding.PeerPort, ip[1], Length(ip));
dss.Free();
except
on E : Exception do
WriteLogFile(E.message);
end;
end;
procedure TForm1.ADDTCPConn(AThread: TIdPeerThread;i:Integer);
var
NewClientIP : String;
begin
NewClientIP := AThread.Connection.Socket.Binding.PeerIP;
//NewClientHostName := IPAddrToName(NewClientIP);
//Add_To_StringGrid(Clients_StringGrid,NewClientIP,'ggg','eee',i);
InsertRow1(Clients_StringGrid,NewClientIP,'ggg','eee');
IncomingText.Lines.Add(TimeToStr(Time)+' Connection from "' + 'ggg' + '" on ' + NewClientIP);
IncomingText.Lines.Add('------------');
StatusBar1.Panels.Items[0].Text := ' Status : TCP Connected';
flag:=true;
end;
Procedure TForm1.Add_To_StringGrid(Grid:TStringGrid; Str1:String; Str2:String; Str3:String;
i:Integer);
Begin
if i=-1 then
begin
if RCount <> 0 then
Grid.RowCount := Grid.RowCount + 1;
RCount:=RCount+1;
Grid.Cells[0,RCount] := Str1;
Grid.Cells[1,RCount] := Str2;
Grid.Cells[2,RCount] := Str3;
end
else
begin
Grid.Cells[0,i] := Str1;
Grid.Cells[1,i] := Str2;
Grid.Cells[2,i] := Str3;
end;
End;
procedure TForm1.InsertRow1(VGrid: TStringGrid; Str1:String; Str2:String; Str3:String);
begin
if RCount<>0 then
VGrid.RowCount:= VGrid.RowCount + 1;
VGrid.Cells[0, VGrid.RowCount - 1]:= Str1;
VGrid.Cells[1, VGrid.RowCount - 1]:= Str2;
VGrid.Cells[2, VGrid.RowCount - 1]:= Str3;
RCount:=RCount+1;
end;
procedure TForm1.DeleteRow1(VGrid: TStringGrid; VRow: integer);
var
I, J: Integer;
begin
if VGrid.RowCount = 2 then
begin
VGrid.Rows[1].CommaText:= '"","","","",""';
end
else
begin
for I:= VRow to VGrid.RowCount - 2 do
for J:=0 to VGrid.ColCount - 1 do
VGrid.Cells[J,I]:= VGrid.Cells[J, I + 1];
VGrid.RowCount:= VGrid.RowCount - 1;
end;
RCount:=RCount-1;
if RCount=0 then
VGrid.RowCount:= 2;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
RCount:=0;
Clients_StringGrid.Cells[0, 0]:= 'Client IP';
Clients_StringGrid.Cells[1, 0]:= 'Host Name';
Clients_StringGrid.Cells[2, 0]:= 'Versa';
end;
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
begin
if flag then
AThread.Connection.WriteLn('Reply')
else
AThread.Connection.WriteLn('Reject');
end;
procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);
var
j:Integer;
fl:Boolean;
IP:String;
IPList2 : TStringList;
Count:Integer;
i:Integer;
begin
try
Count:=StrToInt(Edit3.Text);
IP:= AThread.Connection.Socket.Binding.PeerIP;
if (Clients_StringGrid.Cols[0].IndexOf(IP) = -1) then
begin
if RCount < Count then
begin
if (Clients_StringGrid.Cols[0].IndexOf(IP) = -1) then
ADDTCPConn(AThread,-1)
else
begin
StatusBar1.Panels.Items[0].Text := ' Status : TCP Already Connected';
flag:=True;
end;
end
else
begin
IPList:=TStringList.Create;
IPList2:=TStringList.Create;
fl:=False;
IPList.Clear;
IPList2.Clear;
For i:=1 To Count Do
begin
IdTCPClient1.Host := Clients_StringGrid.Cells[0,i];
IdTCPClient1.Port := 1112;
if IdTCPClient1.connected then
IdTCPClient1.Disconnect;
try
IdTCPClient1.Connect();
IdTCPClient1.Disconnect;
IPList.Add(Clients_StringGrid.Cells[0,i]);
except
on E : Exception do
begin
IPList2.Add(Clients_StringGrid.Cells[0,i]);
fl:=True;
end;
end;
end;
IncomingText.Lines.Add('Num Act ip:'+IntToStr(IPList.Count));
For j:=1 To IPList2.Count Do
begin
IncomingText.Lines.Add('row Del'+IntToStr(Clients_StringGrid.Cols[0].IndexOf(IPList2[j-1])));
DeleteRow1(Clients_StringGrid,Clients_StringGrid.Cols[0].IndexOf(IPList2[j-1]));
end;
if fl then
begin
ADDTCPConn(AThread,-1);
flag:=True;
end
else
flag:=false;
IPList.Free;
IPList2.Free;
end;
end
else
begin
StatusBar1.Panels.Items[0].Text := ' Status : TCP Already Connected';
flag:=True;
end;
except
on E : Exception do
WriteLogFile(E.message);
end;
end;
end.
//Client Side
unit ClientUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, IdAntiFreezeBase, IdAntiFreeze,
IdTCPConnection, IdTCPClient, IdBaseComponent, IdComponent, IdUDPBase,
IdUDPClient, ComCtrls, IdUDPServer,IdSocketHandle,IdStack, IdTCPServer,
IdThreadMgr, IdThreadMgrDefault;
type
TForm2 = class(TForm)
Panel1: TPanel;
Label3: TLabel;
Edit3: TEdit;
Button1: TButton;
Button2: TButton;
Button3: TButton;
StatusBar1: TStatusBar;
GroupBox2: TGroupBox;
IncomingText: TMemo;
IdUDPClient1: TIdUDPClient;
IdTCPClient1: TIdTCPClient;
IdAntiFreeze1: TIdAntiFreeze;
IdTCPServer1: TIdTCPServer;
IdThreadMgrDefault1: TIdThreadMgrDefault;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure IdTCPServer1Execute(AThread: TIdPeerThread);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
ServerIP:String;
implementation
uses CommonUnit;
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
begin
if not IdUDPClient1.Active then
begin
IdUDPClient1.Port:=1717;
IdUDPClient1.BroadcastEnabled:=True;
IdUDPClient1.Active:=True;
IdTCPServer1.Active:=False;
end;
Button1.Enabled:=False;
Button2.Enabled:=True;
end;
procedure TForm2.Button2Click(Sender: TObject);
var
StrIn : String;
StrOut : String;
begin
try
StrOut:='Request';
IdUDPClient1.Broadcast(StrOut, 1717);
StrIn := IdUDPClient1.ReceiveString(100);
if not (StrIn='') then
begin
Button3.Enabled:=True;
Button2.Enabled:=False;
IncomingText.Lines.Add('UDP Reply');
StatusBar1.Panels.Items[0].Text := 'Status : UDP Connected';
ServerIP := StrIn;
end
else
WriteLogFile('UDP Connection Failed');
except
on E : Exception do
WriteLogFile(E.Message);
end;
end;
procedure TForm2.Button3Click(Sender: TObject);
var
StrIn : String;
begin
try
if ServerIP<>'' then
begin
IdTCPClient1.Host := ServerIP ;
IdTCPClient1.Port := 1717 ;
IdTCPClient1.Connect;
StrIn:= IdTCPClient1.ReadLn();
//IdTCPClient1.Disconnect;
if StrIn<>'' then
begin
IncomingText.Lines.Add(StrIn);
if StrIn<>'Reply' then
StatusBar1.Panels.Items[0].Text :='Connected To TCPServer';
else
begin
Button3.Enabled:=False;
Button1.Enabled:=True;
end;
end
else
WriteLogFile('TCP Connection Failed');
end;
except
on E : Exception do
WriteLogFile(E.message);
end;
end;
procedure TForm2.IdTCPServer1Execute(AThread: TIdPeerThread);
begin
//check point
end;
end.
//when in event onconnect on server want to check clients in list , line IdTCPClient1.Connect() return error
1)Socket Error # 10022 Invalid argument.
2)Connection Closed Gracefully.
and never run onexcute on client side
why this hapened
My program stays running if I click the X in the top right hand corner of the form. This also happens within Delphi 4 and I am then forced to do a Program Reset as it will not recomplie if i don't.
Main form code:
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
type
TMainForm = class(TForm)
NewButton: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
ExitButton: TButton;
LockButton: TButton;
SettingsButton: TButton;
Label1: TLabel;
TimeLabel: TLabel;
Timer1: TTimer;
procedure ExitButtonClick(Sender: TObject);
procedure LockButtonClick(Sender: TObject);
procedure SettingsButtonClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure NewButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
uses Unit2, Unit1, Unit4;
{$R *.DFM}
procedure TMainForm.ExitButtonClick(Sender: TObject);
begin
if MessageBox(0, 'Are you sure you want to quit?', 'Exit Program?', +mb_YesNo +mb_ICONWARNING) = 6 then
Application.Terminate
else
end;
procedure TMainForm.LockButtonClick(Sender: TObject);
begin
MainForm.Hide;
Login.Show;
Login.LockLabel.Visible := true;
end;
procedure TMainForm.SettingsButtonClick(Sender: TObject);
begin
MainForm.Hide;
Settings.Show;
end;
procedure TMainForm.Timer1Timer(Sender: TObject);
begin
TimeLabel.Caption := TimeToStr(time);
end;
procedure TMainForm.NewButtonClick(Sender: TObject);
begin
TransForm.Show;
MainForm.Hide;
end;
end.
Login Form code:
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Mask, inifiles, Unit1;
type
TLogin = class(TForm)
PassEdit: TMaskEdit;
LoginButton: TButton;
PassLabel: TLabel;
InvisiButton: TButton;
LockLabel: TLabel;
procedure PassEditClick(Sender: TObject);
procedure LoginButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Login: TLogin;
IniFile : TIniFile;
appINI : TIniFile;
Password : string;
implementation
uses Unit3;
{$R *.DFM}
procedure TLogin.PassEditClick(Sender: TObject);
begin
PassEdit.Text := '';
end;
procedure TLogin.LoginButtonClick(Sender: TObject);
begin
if Password = PassEdit.Text then begin
Login.Hide;
MainForm.Show;
LockLabel.Visible := false;
end
else
showmessage('Incorrect Password!')
end;
procedure TLogin.FormCreate(Sender: TObject);
begin
appINI := TIniFile.Create(ChangeFileExt(Application.ExeName,'.ini'));
Password := appINI.ReadString('Login','Password','');
appINI.Free;
end;
end.
Setting Form Code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, inifiles;
type
TSettings = class(TForm)
SaveButton: TButton;
AEditA: TEdit;
AEditB: TEdit;
SEditB: TEdit;
PEditB: TEdit;
PLabelA: TLabel;
SLabelA: TLabel;
ALabelA: TLabel;
PEditA: TEdit;
SEditA: TEdit;
BackButton: TButton;
SettingsLabel: TLabel;
ALabelB: TLabel;
SLabelB: TLabel;
PLabelB: TLabel;
AReserveLabel: TLabel;
BReserveLabel: TLabel;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label8: TLabel;
Label7: TLabel;
procedure SaveButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure BackButtonClick(Sender: TObject);
procedure AEditAKeyPress(Sender: TObject; var Key: Char);
procedure AEditBKeyPress(Sender: TObject; var Key: Char);
procedure SEditAKeyPress(Sender: TObject; var Key: Char);
procedure SEditBKeyPress(Sender: TObject; var Key: Char);
procedure PEditAKeyPress(Sender: TObject; var Key: Char);
procedure PEditBKeyPress(Sender: TObject; var Key: Char);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Settings: TSettings;
IniFile : TIniFile;
appINI : TIniFile;
APriceA : String;
SPriceA : String;
PPriceA : String;
APriceB : String;
SPriceB : String;
PPriceB : String;
change : boolean;
implementation
uses Unit3, Unit2;
{$R *.DFM}
procedure TSettings.SaveButtonClick(Sender: TObject);
//Save Button
begin
appINI := TIniFile.Create(ChangeFileExt(Application.ExeName,'.ini'));
APriceA := (AEditA.Text);
SPriceA := (SEditA.Text);
PPriceA := (PEditA.Text);
APriceB := (AEditB.Text);
SPriceB := (SEditB.Text);
PPriceB := (PEditB.Text);
appINI.WriteString('PricesA','Adult',APriceA);
appINI.WriteString('PricesA','Student',SPriceA);
appINI.WriteString('PricesA','Pensioner',PPriceA);
appINI.WriteString('PricesB','Adult',APriceB);
appINI.WriteString('PricesB','Student',SPriceB);
appINI.WriteString('PricesB','Pensioner',PPriceB);
appINI.Free;
ShowMessage('Settings Saved Successfully!');
change := false;
end;
procedure TSettings.FormCreate(Sender: TObject);
//Displays values as the form is created
begin
appINI := TIniFile.Create(ChangeFileExt(Application.ExeName,'.ini'));
APriceA := appINI.ReadString('PricesA','Adult','');
SPriceA := appINI.ReadString('PricesA','Student','');
PPriceA := appINI.ReadString('PricesA','Pensioner','');
APriceB := appINI.ReadString('PricesB','Adult','');
SPriceB := appINI.ReadString('PricesB','Student','');
PPriceB := appINI.ReadString('PricesB','Pensioner','');
appINI.Free;
AEditA.Text := (APriceA);
SEditA.Text := (SPriceA);
PEditA.Text := (PPriceA);
AEditB.Text := (APriceB);
SEditB.Text := (SPriceB);
PEditB.Text := (PPriceB);
end;
procedure TSettings.BackButtonClick(Sender: TObject);
//Exit Button
begin
if MessageBox(0, 'Are you sure you want to quit?', 'Exit Program?', +mb_YesNo +mb_ICONWARNING) = 6 then begin
if Change = (true) then
begin
if MessageBox(0, 'Save Changes?', 'Save Changes?', +mb_YesNo +mb_ICONWARNING) = 6 then
begin
appINI := TIniFile.Create(ChangeFileExt(Application.ExeName,'.ini'));
APriceA := (AEditA.Text);
SPriceA := (SEditA.Text);
PPriceA := (PEditA.Text);
APriceB := (AEditB.Text);
SPriceB := (SEditB.Text);
PPriceB := (PEditB.Text);
appINI.WriteString('PricesA','Adult',APriceA);
appINI.WriteString('PricesA','Student',SPriceA);
appINI.WriteString('PricesA','Pensioner',PPriceA);
appINI.WriteString('PricesB','Adult',APriceB);
appINI.WriteString('PricesB','Student',SPriceB);
appINI.WriteString('PricesB','Pensioner',PPriceB);
appINI.Free;
ShowMessage('Settings Saved Successfully!');
Settings.Hide;
MainForm.Show;
change := false;
end
else
change := false;
MainForm.Show;
Settings.Hide;
end
else
MainForm.Show;
Settings.Hide;
end
else
end;
procedure TSettings.AEditAKeyPress(Sender: TObject; var Key: Char);
var s:string;
begin
change := true;
s := ('1234567890.'#8); //Add chars you want to allow
if pos(key,s) =0 then begin
Key:=#0;
showmessage('Only Numbers are allowed. Include cents!');
end;
end;
procedure TSettings.AEditBKeyPress(Sender: TObject; var Key: Char);
var s:string;
begin
change := true;
s := ('1234567890.'#8); //Add chars you want to allow
if pos(key,s) =0 then begin
Key:=#0;
showmessage('Only Numbers are allowed. Include cents!');
end;
end;
procedure TSettings.SEditAKeyPress(Sender: TObject; var Key: Char);
var s:string;
begin
change := true;
s := ('1234567890.'#8); //Add chars you want to allow
if pos(key,s) =0 then begin
Key:=#0;
showmessage('Only Numbers are allowed. Include cents!');
end;
end;
procedure TSettings.SEditBKeyPress(Sender: TObject; var Key: Char);
var s:string;
begin
change := true;
s := ('1234567890.'#8); //Add chars you want to allow
if pos(key,s) =0 then begin
Key:=#0;
showmessage('Only Numbers are allowed. Include cents!');
end;
end;
procedure TSettings.PEditAKeyPress(Sender: TObject; var Key: Char);
var s:string;
begin
change := true;
s := ('1234567890.'#8); //Add chars you want to allow
if pos(key,s) =0 then begin
Key:=#0;
showmessage('Only Numbers are allowed. Include cents!');
end;
end;
procedure TSettings.PEditBKeyPress(Sender: TObject; var Key: Char);
var s:string;
begin
change := true;
s := ('1234567890.'#8); //Add chars you want to allow
if pos(key,s) =0 then begin
Key:=#0;
showmessage('Only Numbers are allowed. Include cents!');
end;
end;
//End of Settings
procedure TSettings.Button1Click(Sender: TObject);
begin
Settings.hide;
end;
end.
Project Data:
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Settings},
Unit2 in 'Unit2.pas' {Login},
Unit3 in 'Unit3.pas' {MainForm},
Unit4 in '..\Write to ini\Unit4.pas' {TransForm};
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(TLogin, Login);
Application.CreateForm(TMainForm, MainForm);
Application.CreateForm(TSettings, Settings);
Application.Run;
end.
When i close the application it stays running, can you help me fix this?
As David said, your TLogin form is being set as Application.MainForm because it is the first form create by Application.CreateForm(). You are simply hiding the TLogin form, not closing it, which is why your app does not fully exit. When you close the TMainForm form, the TLogin form is still running.
Given the code you have shown, your TMainForm form should be the only one created with Application.CreateForm(). All of your other forms should be created on an as-needed basis instead.
You have also coded Unit1, Unit2, and Unit3 (what is Unit4?) to be inter-dependant on each other when they do not need to be, so you should remove that dependancy as well. The TLogin and TSettings units should be standalone units.
Try something more like this instead:
Main form:
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
type
TMainForm = class(TForm)
NewButton: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
ExitButton: TButton;
LockButton: TButton;
SettingsButton: TButton;
Label1: TLabel;
TimeLabel: TLabel;
Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure ExitButtonClick(Sender: TObject);
procedure LockButtonClick(Sender: TObject);
procedure SettingsButtonClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure NewButtonClick(Sender: TObject);
protected
procedure WndProc(var Message: TMessage); override;
private
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
uses
Unit2, Unit1, Unit4;
{$R *.DFM}
const
WM_LOCK = WM_USER + 100;
procedure TMainForm.FormCreate(Sender: TObject);
begin
PostMessage(Handle, WM_LOCK, 0, 0);
end;
procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if Application.MessageBox('Are you sure you want to quit?', 'Exit Program?', MB_YESNO or MB_ICONWARNING) <> IDYES then
CanClose := False;
end;
procedure TMainForm.WndProc(var Message: TMessage);
begin
if Message.Msg = WM_LOCK then
LockButtonClick(nil)
else
inherited;
end;
procedure TMainForm.ExitButtonClick(Sender: TObject);
begin
Close;
end;
procedure TMainForm.LockButtonClick(Sender: TObject);
var
Login: TLogin;
begin
Login := TLogin.Create(nil);
try
Hide;
Login.LockLabel.Visible := True;
if Login.ShowModal = mrOk then
Show
else
Application.Terminate;
finally
Login.Free;
end;
end;
procedure TMainForm.SettingsButtonClick(Sender: TObject);
var
Settings: TSettings;
begin
Settings := TSettings.Create(nil);
try
Settings.ShowModal;
finally
Settings.Free;
end;
end;
procedure TMainForm.Timer1Timer(Sender: TObject);
begin
TimeLabel.Caption := TimeToStr(time);
end;
procedure TMainForm.NewButtonClick(Sender: TObject);
begin
TransForm.Show;
Hide;
end;
end.
Login form:
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Mask;
type
TLogin = class(TForm)
PassEdit: TMaskEdit;
LoginButton: TButton;
PassLabel: TLabel;
InvisiButton: TButton;
LockLabel: TLabel;
procedure PassEditClick(Sender: TObject);
procedure LoginButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
implementation
uses
inifiles;
var
Password : string;
{$R *.DFM}
procedure TLogin.FormCreate(Sender: TObject);
var
appINI : TIniFile;
begin
appINI := TIniFile.Create(ChangeFileExt(Application.ExeName,'.ini'));
try
Password := appINI.ReadString('Login','Password','');
finally
appINI.Free;
end;
end;
procedure TLogin.PassEditClick(Sender: TObject);
begin
PassEdit.Text := '';
end;
procedure TLogin.LoginButtonClick(Sender: TObject);
begin
if Password <> PassEdit.Text then
begin
ShowMessage('Incorrect Password!')
Exit;
end;
LockLabel.Visible := False;
ModalResult = mrOk;
end;
end.
Settings Form:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TSettings = class(TForm)
SaveButton: TButton;
AEditA: TEdit;
AEditB: TEdit;
SEditB: TEdit;
PEditB: TEdit;
PLabelA: TLabel;
SLabelA: TLabel;
ALabelA: TLabel;
PEditA: TEdit;
SEditA: TEdit;
BackButton: TButton;
SettingsLabel: TLabel;
ALabelB: TLabel;
SLabelB: TLabel;
PLabelB: TLabel;
AReserveLabel: TLabel;
BReserveLabel: TLabel;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label8: TLabel;
Label7: TLabel;
procedure SaveButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure BackButtonClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
function Changed: Boolean;
function SaveSettings: Boolean;
public
{ Public declarations }
end;
var
APriceA : String;
SPriceA : String;
PPriceA : String;
APriceB : String;
SPriceB : String;
PPriceB : String;
implementation
uses
inifiles;
{$R *.DFM}
procedure LoadSettings;
var
appINI: TIniFile;
begin
appINI := TIniFile.Create(ChangeFileExt(Application.ExeName,'.ini'));
try
APriceA := appINI.ReadString('PricesA','Adult','');
SPriceA := appINI.ReadString('PricesA','Student','');
PPriceA := appINI.ReadString('PricesA','Pensioner','');
APriceB := appINI.ReadString('PricesB','Adult','');
SPriceB := appINI.ReadString('PricesB','Student','');
PPriceB := appINI.ReadString('PricesB','Pensioner','');
finally
appINI.Free;
end;
end;
procedure TSettings.FormCreate(Sender: TObject);
begin
AEditA.Text := APriceA;
AEditA.Modified := False;
SEditA.Text := SPriceA;
SEditA.Modified := False;
PEditA.Text := PPriceA;
PEditA.Modified := False;
AEditB.Text := APriceB;
AEditB.Modified := False;
SEditB.Text := SPriceB;
SEditB.Modified := False;
PEditB.Text := PPriceB;
PEditB.Modified := False;
end;
function TSettings.Changed: Boolean;
begin
Result := AEditA.Modified or
SEditA.Modified or
PEditA.Modified or
AEditB.Modified or
SEditB.Modified or
PEditB.Modified;
end;
function TSettings.SaveSettings: Boolean;
var
dbl: Double;
begin
Result := TryStrToFloat(AEditA.Text, dbl) and
TryStrToFloat(SEditA.Text, dbl) and
TryStrToFloat(PEditA.Text, dbl) and
TryStrToFloat(AEditB.Text, dbl) and
TryStrToFloat(SEditB.Text, dbl) and
TryStrToFloat(PEditB.Text, dbl);
if not Result then
begin
ShowMessage('Only Numbers are allowed. Include cents!');
Exit;
end;
APriceA := AEditA.Text;
SPriceA := SEditA.Text;
PPriceA := PEditA.Text;
APriceB := AEditB.Text;
SPriceB := SEditB.Text;
PPriceB := PEditB.Text;
appINI := TIniFile.Create(ChangeFileExt(Application.ExeName,'.ini'));
try
appINI.WriteString('PricesA','Adult',APriceA);
appINI.WriteString('PricesA','Student',SPriceA);
appINI.WriteString('PricesA','Pensioner',PPriceA);
appINI.WriteString('PricesB','Adult',APriceB);
appINI.WriteString('PricesB','Student',SPriceB);
appINI.WriteString('PricesB','Pensioner',PPriceB);
finally
appINI.Free;
end;
AEditA.Modified := False;
SEditA.Modified := False;
PEditA.Modified := False;
AEditB.Modified := False;
SEditB.Modified := False;
PEditB.Modified := False;
ShowMessage('Settings Saved Successfully!');
Result := True;
end;
procedure TSettings.SaveButtonClick(Sender: TObject);
begin
SaveSettings;
end;
procedure TSettings.BackButtonClick(Sender: TObject);
begin
if Changed then
begin
if Application.MessageBox('Save Changes?', 'Save Changes?', MB_YESNO or MB_ICONWARNING) = IDYES then
begin
if not SaveSettings then
Exit;
end;
end;
ModalResult = mrOk;
end;
procedure TSettings.Button1Click(Sender: TObject);
begin
Close;
end;
initialization
LoadSettings;
end.
Project:
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Settings},
Unit2 in 'Unit2.pas' {Login},
Unit3 in 'Unit3.pas' {MainForm},
Unit4 in '..\Write to ini\Unit4.pas' {TransForm};
{$R *.RES}
begin
Application.Initialize;
Application.CreateForm(TMainForm, MainForm);
Application.ShowMainForm := False;
Application.Run;
end.
The easiest way to to this would be to be in a close button with just one line of code:
BtnClose.click
Begin
Application.terminate;
End;
Hope that helps