MainForm.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 22939: MainForm.pas
  11. {
  12. { Rev 1.0 09/10/2003 3:08:58 PM Jeremy Darling
  13. { Project Checked into TC for the first time
  14. }
  15. {***************************************************************
  16. * Project : <This is the name of your project>
  17. * Unit Name: <This is the name of this unit>
  18. * Purpose : <This is a description of the project>
  19. * Author : <Your Name>
  20. * Date : <Date submitted to indy demo team>
  21. * Other Info : <Anything else>
  22. * History :
  23. * <History list>
  24. ****************************************************************}
  25. unit MainForm;
  26. interface
  27. uses
  28. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  29. IdBaseComponent, IdComponent, IdTCPServer, IdContext, StdCtrls, IdScheduler,
  30. IdSchedulerOfThread, IdSchedulerOfThreadDefault, CheckLst, ComCtrls, ExtCtrls,
  31. IdDsnCoreResourceStrings, IdStack, IdSocketHandle, ShellAPI, IdGlobal,
  32. IniFiles, IdAntiFreezeBase, IdAntiFreeze, IdCustomTCPServer, IdStackWindows;
  33. type
  34. TfrmMain = class(TForm)
  35. Server: TIdTCPServer;
  36. pnlButtonBar: TPanel;
  37. pcMain: TPageControl;
  38. tsSettings: TTabSheet;
  39. Label2: TLabel;
  40. Label3: TLabel;
  41. Label4: TLabel;
  42. lbIPs: TCheckListBox;
  43. cbPorts: TComboBox;
  44. edPort: TEdit;
  45. tsProcessLog: TTabSheet;
  46. lbProcesses: TListBox;
  47. btnStartStop: TButton;
  48. IdAntiFreeze1: TIdAntiFreeze;
  49. IdSchedulerOfThreadDefault1: TIdSchedulerOfThreadDefault;
  50. procedure btnStartStopClick(Sender: TObject);
  51. procedure FormCreate(Sender: TObject);
  52. procedure FormDestroy(Sender: TObject);
  53. procedure lbProcessesDrawItem(Control: TWinControl; Index: Integer;
  54. Rect: TRect; State: TOwnerDrawState);
  55. procedure ServerStatus(ASender: TObject; const AStatus: TIdStatus;
  56. const AStatusText: String);
  57. procedure ServerException(AContext: TIdContext; AException: Exception);
  58. procedure FormActivate(Sender: TObject);
  59. procedure ServerExecute(AContext: TIdContext);
  60. procedure ServerConnect(AContext: TIdContext);
  61. procedure ServerDisconnect(AContext: TIdContext);
  62. procedure edPortKeyPress(Sender: TObject; var Key: Char);
  63. private
  64. { Private declarations }
  65. function CheckStartOk : Boolean;
  66. function StartServer : Boolean;
  67. function StopServer : Boolean;
  68. procedure PopulateIPAddresses;
  69. function PortDescription(const PortNumber: integer): string;
  70. procedure LoadDefaultValues;
  71. procedure SaveDefaultValues;
  72. procedure CheckOptions;
  73. function GetServerOnline: Boolean;
  74. function InternalServerBeforeStart : Boolean;
  75. procedure InternalServerAfterStart;
  76. function InternalServerBeforeStop : Boolean;
  77. procedure InternalServerAfterStop;
  78. procedure Log(Msg : String; Color : TColor = clBlack);
  79. procedure SetControls;
  80. public
  81. { Public declarations }
  82. property ServerOnline : Boolean read GetServerOnline;
  83. end;
  84. var
  85. frmMain : TfrmMain;
  86. Ini : TIniFile;
  87. implementation
  88. {$R *.DFM}
  89. procedure TfrmMain.btnStartStopClick(Sender: TObject);
  90. begin
  91. // This procedure should never change.
  92. if ServerOnline then
  93. StopServer
  94. else
  95. StartServer;
  96. end;
  97. function TfrmMain.CheckStartOk: Boolean;
  98. var
  99. i, c : Integer;
  100. begin
  101. // This section should stay the same, add your new code below
  102. i := 0;
  103. for c := 0 to lbIPs.Items.Count -1 do
  104. begin
  105. if lbIPs.Checked[c] then
  106. inc(i);
  107. end;
  108. result := i > 0;
  109. if not result then
  110. begin
  111. Log('Can''t start server until you select at least one IP to bind to.', clRed);
  112. MessageDlg('Can''t start server until you select at least one IP to bind to.', mtError, [mbOK], 0);
  113. end;
  114. // Add your code after this comment
  115. end;
  116. procedure TfrmMain.PopulateIPAddresses;
  117. var
  118. i : integer;
  119. begin
  120. // Again this section should not change
  121. with lbIPs do
  122. begin
  123. Clear;
  124. Items := GStack.LocalAddresses;
  125. Items.Insert(0, '127.0.0.1');
  126. end;
  127. try
  128. cbPorts.Items.Add(RSBindingAny);
  129. cbPorts.Items.BeginUpdate;
  130. for i := 0 to IdPorts.Count - 1 do
  131. cbPorts.Items.Add(PortDescription(Integer(IdPorts[i])));
  132. finally
  133. cbPorts.Items.EndUpdate;
  134. end;
  135. end;
  136. function TfrmMain.PortDescription(const PortNumber: integer): string;
  137. begin
  138. // Guess what more code that shouldn't change
  139. with TIdStackWindows(GStack).WSGetServByPort(PortNumber) do
  140. try
  141. if PortNumber = 0 then
  142. begin
  143. Result := Format('%d: %s', [PortNumber, RSBindingAny]);
  144. end
  145. else
  146. begin
  147. Result := ''; {Do not Localize}
  148. if Count > 0 then
  149. begin
  150. Result := Format('%d: %s', [PortNumber, CommaText]); {Do not Localize}
  151. end;
  152. end;
  153. finally
  154. Free;
  155. end;
  156. end;
  157. function TfrmMain.StartServer: Boolean;
  158. var
  159. Binding : TIdSocketHandle;
  160. i : integer;
  161. SL : TStringList;
  162. begin
  163. // This code starts the server up and posts back information about
  164. // the server starting up.
  165. // You should place your pre and post startup code in InternalServerBeforeStart
  166. // and InternalServerAfterStart accordingly.
  167. Result := false;
  168. if not CheckStartOk then
  169. exit;
  170. SL := TStringList.Create;
  171. if not StopServer then
  172. begin
  173. Log( 'Error stopping server', clRed );
  174. Result := false;
  175. exit;
  176. end;
  177. Server.Bindings.Clear; // bindings cannot be cleared until TServer is inactive
  178. try
  179. try
  180. Server.DefaultPort := StrToInt(edPort.Text);
  181. for i := 0 to lbIPs.Items.Count - 1 do
  182. if lbIPs.Checked[i] then
  183. begin
  184. Binding := Server.Bindings.Add;
  185. Binding.IP := lbIPs.Items.Strings[i];
  186. Binding.Port := StrToInt( edPort.Text );
  187. Log( 'Server bound to IP ' + Binding.IP + ' on port ' + edPort.Text );
  188. end;
  189. if InternalServerBeforeStart then
  190. begin
  191. Server.Active := true;
  192. result := Server.Active;
  193. InternalServerAfterStart;
  194. if ServerOnline then
  195. begin
  196. Log( 'Server started', clGreen );
  197. btnStartStop.Caption := 'Stop Server';
  198. SetControls;
  199. end;
  200. end;
  201. except
  202. on E : Exception do
  203. begin
  204. Log( 'Server not started', clRed );
  205. Log( E.Message, clRed );
  206. Result := false;
  207. end;
  208. end;
  209. finally
  210. FreeAndNil( SL );
  211. end;
  212. end;
  213. function TfrmMain.StopServer: Boolean;
  214. var
  215. b : Boolean;
  216. begin
  217. // This code stops the server and posts back information about
  218. // the server shutting down.
  219. // You should place your pre and post shutdown code in InternalServerBeforeStop
  220. // and InternalServerAfterStop accordingly.
  221. Result := false;
  222. b := Server.Active;
  223. if InternalServerBeforeStop then
  224. begin
  225. Server.Active := false;
  226. Server.Bindings.Clear;
  227. Result := not Server.Active;
  228. if result then
  229. begin
  230. if b then
  231. Log( 'Server stopped', clGreen );
  232. end
  233. else
  234. begin
  235. Log( 'Server not stopped', clRed );
  236. end;
  237. InternalServerAfterStop;
  238. btnStartStop.Caption := 'Start Server';
  239. SetControls;
  240. end
  241. else
  242. Log( 'Server not stopped', clRed );
  243. end;
  244. procedure TfrmMain.FormCreate(Sender: TObject);
  245. begin
  246. // Initialization routines. You should find the appropriate procedure
  247. // to initialize your stuff below. The form create should hardly ever
  248. // need to be changed.
  249. Ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini'));
  250. pcMain.ActivePageIndex := 0;
  251. pcMain.Align := alClient;
  252. PopulateIPAddresses;
  253. StopServer;
  254. LoadDefaultValues;
  255. CheckOptions;
  256. end;
  257. procedure TfrmMain.FormDestroy(Sender: TObject);
  258. begin
  259. // If you created anything in form create or in one of the other
  260. // initialization routines then get rid of it here.
  261. StopServer;
  262. SaveDefaultValues;
  263. Ini.Free;
  264. end;
  265. procedure TfrmMain.LoadDefaultValues;
  266. var
  267. i, c : Integer;
  268. s : String;
  269. begin
  270. // This is were you get the chance to load values from the global
  271. // Ini file. The section for ports and IP's has been added in here
  272. // for you by default.
  273. edPort.Text := Ini.ReadString('Settings', 'Port', edPort.Text);
  274. c := Ini.ReadInteger('Settings', 'IPs', 0);
  275. for i := 1 to c do
  276. begin
  277. s := Ini.ReadString('Settings', 'IP' + IntToStr(i), '');
  278. if lbIPs.Items.IndexOf(s) > -1 then
  279. lbIPs.Checked[lbIPs.Items.IndexOf(s)] := true;
  280. end;
  281. end;
  282. procedure TfrmMain.SaveDefaultValues;
  283. var
  284. i, c : Integer;
  285. begin
  286. // This is were you get the chance to save values to the global
  287. // Ini file. The section for ports and IP's has been added in here
  288. // for you by default.
  289. Ini.WriteString('Settings', 'Port', edPort.Text);
  290. c := 0;
  291. for i := 0 to lbIPs.Items.Count -1 do
  292. if lbIPs.Checked[i] then
  293. begin
  294. inc(c);
  295. Ini.WriteString('Settings', 'IP' + IntToStr(c), lbIPs.Items[i]);
  296. end;
  297. Ini.WriteInteger('Settings', 'IPs', c);
  298. Ini.WriteInteger('Placement', 'Top', Top);
  299. Ini.WriteInteger('Placement', 'Left', Left);
  300. end;
  301. procedure TfrmMain.CheckOptions;
  302. var
  303. i : Integer;
  304. opt : string;
  305. bDoAutoStart : Boolean;
  306. function OptName : String;
  307. begin
  308. if pos('=', opt) > 0 then
  309. begin
  310. result := copy(opt, 1, pos('=', opt) - 1);
  311. if result[1] in ['-', '/', '\'] then
  312. result := copy(result, 2, length(result));
  313. end
  314. else
  315. result := opt;
  316. end;
  317. function OptValue : String;
  318. begin
  319. if pos('=', opt) > 0 then
  320. result := copy(opt, pos('=', opt) + 1, length(opt))
  321. else
  322. result := opt;
  323. end;
  324. begin
  325. // The check options procedure should be used to check commandline options
  326. // if you wish to support command line options then please add it here.
  327. // By default port and autostart are supported.
  328. bDoAutoStart := false;
  329. for i := 1 to ParamCount do
  330. begin
  331. opt := LowerCase(ParamStr(i));
  332. if OptName = 'port' then
  333. edPort.Text := OptValue;
  334. if OptName = 'autostart' then
  335. bDoAutoStart := true;
  336. end;
  337. if bDoAutoStart then
  338. StartServer;
  339. end;
  340. function TfrmMain.GetServerOnline: Boolean;
  341. begin
  342. // Just a faster way then checking server.active for some
  343. result := Server.Active;
  344. end;
  345. procedure TfrmMain.lbProcessesDrawItem(Control: TWinControl;
  346. Index: Integer; Rect: TRect; State: TOwnerDrawState);
  347. begin
  348. // This draws the items in the Process Log in colors to allow quick
  349. // visual inspection
  350. with Control as TListBox do
  351. begin
  352. Canvas.Brush.Color := Color;
  353. Canvas.FillRect(Rect);
  354. Canvas.Font.Color := TColor(Items.Objects[Index]);
  355. Canvas.TextOut(Rect.Left + 2, Rect.Top, Items[Index]);
  356. end;
  357. end;
  358. procedure TfrmMain.Log(Msg: String; Color: TColor);
  359. begin
  360. // Simply adds a new item to the process log and then makes it the
  361. // currently selected item.
  362. lbProcesses.Items.AddObject(Msg, Pointer(Color));
  363. lbProcesses.ItemIndex := lbProcesses.Items.Count -1;
  364. end;
  365. procedure TfrmMain.ServerStatus(ASender: TObject; const AStatus: TIdStatus;
  366. const AStatusText: String);
  367. begin
  368. // Logs any ServerStatus messages to the Process Log
  369. Log(AStatusText);
  370. end;
  371. procedure TfrmMain.ServerException(AContext: TIdContext;
  372. AException: Exception);
  373. begin
  374. // Logs any server exceptions to the Process Log
  375. Log(AException.Message, clRed);
  376. end;
  377. function TfrmMain.InternalServerBeforeStart: Boolean;
  378. begin
  379. // Preform your startup code here. If you do not wish the server to start
  380. // then simply return false from this function and report back the proper
  381. // error by calling Log(YourMessage, clRed);
  382. result := true;
  383. end;
  384. procedure TfrmMain.InternalServerAfterStart;
  385. begin
  386. // Your code should go here. At this point the server is active.
  387. // So if you need to stop it then you should call StopServer
  388. // or for a hard halt call Server.Active := false;
  389. end;
  390. procedure TfrmMain.InternalServerAfterStop;
  391. begin
  392. // Your code should go here. At this point the server has been stoped.
  393. // So if you need to start it then you should call StartServer
  394. // or for a force start call Server.Active := true;
  395. end;
  396. function TfrmMain.InternalServerBeforeStop: Boolean;
  397. begin
  398. // Preform your shutdown code here. If you do not wish the server to stop
  399. // then simply return false from this function and report back the proper
  400. // error by calling Log(YourMessage, clRed);
  401. Result := true;
  402. end;
  403. procedure TfrmMain.SetControls;
  404. begin
  405. // Sets up the UI controls to either be enabled or disabled based upon
  406. // the current server state. See below for examples.
  407. lbIPs.Enabled := not ServerOnline;
  408. edPort.Enabled := not ServerOnline;
  409. cbPorts.Enabled := not ServerOnline;
  410. end;
  411. procedure TfrmMain.FormActivate(Sender: TObject);
  412. begin
  413. Top := Ini.ReadInteger('Placement', 'Top', Top);
  414. Left:= Ini.ReadInteger('Placement', 'Left', Left);
  415. end;
  416. procedure TfrmMain.ServerExecute(AContext: TIdContext);
  417. begin
  418. // Your stuff for OnExecute goes here.
  419. end;
  420. procedure TfrmMain.ServerConnect(AContext: TIdContext);
  421. begin
  422. Log('Client connection established from ip: ' + AContext.Connection.Socket.Host, clBlue);
  423. end;
  424. procedure TfrmMain.ServerDisconnect(AContext: TIdContext);
  425. begin
  426. Log('Client connection removed from ip: ' + AContext.Connection.Socket.Host, clBlue);
  427. end;
  428. procedure TfrmMain.edPortKeyPress(Sender: TObject; var Key: Char);
  429. begin
  430. if not (Key in ['0', '1'..'9', #8]) then
  431. Key := #0;
  432. end;
  433. end.