home *** CD-ROM | disk | FTP | other *** search
/ Delphi Anthology / aDELPHI.iso / Runimage / Delphi50 / Source / Vcl / scktmain.pas < prev    next >
Pascal/Delphi Source File  |  1999-08-11  |  25KB  |  887 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Borland Delphi Visual Component Library         }
  5. {       Borland Socket Server source code               }
  6. {                                                       }
  7. {       Copyright (c) 1997,99 Inprise Corporation       }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11. unit ScktMain;
  12.  
  13. interface
  14.  
  15. uses
  16.   SvcMgr, Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  17.   Dialogs, Menus, ShellAPI, ExtCtrls, StdCtrls, ComCtrls, ScktComp, Registry,
  18.   ActnList;
  19.  
  20. const
  21.   WM_MIDASICON    = WM_USER + 1;
  22.   UI_INITIALIZE   = WM_MIDASICON + 1;
  23.  
  24. type
  25.  
  26.   TSocketProc = procedure(Item: TListItem; Socket: TCustomWinSocket) of Object;
  27.  
  28.   TSocketForm = class(TForm)
  29.     PopupMenu: TPopupMenu;
  30.     miClose: TMenuItem;
  31.     N1: TMenuItem;
  32.     miProperties: TMenuItem;
  33.     UpdateTimer: TTimer;
  34.     MainMenu1: TMainMenu;
  35.     miPorts: TMenuItem;
  36.     miAdd: TMenuItem;
  37.     miRemove: TMenuItem;
  38.     Pages: TPageControl;
  39.     PropPage: TTabSheet;
  40.     PortGroup: TGroupBox;
  41.     Label1: TLabel;
  42.     PortDesc: TLabel;
  43.     PortNo: TEdit;
  44.     PortUpDown: TUpDown;
  45.     ThreadGroup: TGroupBox;
  46.     Label4: TLabel;
  47.     ThreadDesc: TLabel;
  48.     ThreadSize: TEdit;
  49.     ThreadUpDown: TUpDown;
  50.     InterceptGroup: TGroupBox;
  51.     Label5: TLabel;
  52.     GUIDDesc: TLabel;
  53.     StatPage: TTabSheet;
  54.     ConnectionList: TListView;
  55.     Connections1: TMenuItem;
  56.     miShowHostName: TMenuItem;
  57.     miDisconnect: TMenuItem;
  58.     N2: TMenuItem;
  59.     TimeoutGroup: TGroupBox;
  60.     Label7: TLabel;
  61.     Timeout: TEdit;
  62.     TimeoutUpDown: TUpDown;
  63.     TimeoutDesc: TLabel;
  64.     InterceptGUID: TEdit;
  65.     ApplyButton: TButton;
  66.     ActionList1: TActionList;
  67.     ApplyAction: TAction;
  68.     DisconnectAction: TAction;
  69.     ShowHostAction: TAction;
  70.     RemovePortAction: TAction;
  71.     N3: TMenuItem;
  72.     miExit: TMenuItem;
  73.     Panel1: TPanel;
  74.     PortList: TListBox;
  75.     HeaderControl1: THeaderControl;
  76.     UserStatus: TStatusBar;
  77.     ExportedObjectOnly1: TMenuItem;
  78.     RegisteredAction: TAction;
  79.     procedure FormCreate(Sender: TObject);
  80.     procedure FormDestroy(Sender: TObject);
  81.     procedure miCloseClick(Sender: TObject);
  82.     procedure miPropertiesClick(Sender: TObject);
  83.     procedure FormShow(Sender: TObject);
  84.     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  85.     procedure miDisconnectClick(Sender: TObject);
  86.     procedure miExitClick(Sender: TObject);
  87.     procedure ApplyActionExecute(Sender: TObject);
  88.     procedure ApplyActionUpdate(Sender: TObject);
  89.     procedure DisconnectActionUpdate(Sender: TObject);
  90.     procedure ShowHostActionExecute(Sender: TObject);
  91.     procedure miAddClick(Sender: TObject);
  92.     procedure RemovePortActionUpdate(Sender: TObject);
  93.     procedure RemovePortActionExecute(Sender: TObject);
  94.     procedure UpDownClick(Sender: TObject; Button: TUDBtnType);
  95.     procedure PortListClick(Sender: TObject);
  96.     procedure ConnectionListCompare(Sender: TObject; Item1,
  97.       Item2: TListItem; Data: Integer; var Compare: Integer);
  98.     procedure ConnectionListColumnClick(Sender: TObject;
  99.       Column: TListColumn);
  100.     procedure IntegerExit(Sender: TObject);
  101.     procedure UpdateTimerTimer(Sender: TObject);
  102.     procedure RegisteredActionExecute(Sender: TObject);
  103.   private
  104.     FTaskMessage: DWord;
  105.     FIconData: TNotifyIconData;
  106.     FClosing: Boolean;
  107.     FProgmanOpen: Boolean;
  108.     FFromService: Boolean;
  109.     NT351: Boolean;
  110.     FCurItem: Integer;
  111.     FSortCol: Integer;
  112.     procedure UpdateStatus;
  113.     function GetSelectedSocket: TServerSocket;
  114.     function GetItemIndex: Integer;
  115.     procedure SetItemIndex(Value: Integer);
  116.     procedure CheckValues;
  117.   protected
  118.     procedure AddClient(Thread: TServerClientThread);
  119.     procedure RemoveClient(Thread: TServerClientThread);
  120.     procedure ClearModifications;
  121.     procedure UIInitialize(var Message: TMessage); message UI_INITIALIZE;
  122.     procedure WMMIDASIcon(var Message: TMessage); message WM_MIDASICON;
  123.     procedure AddIcon;
  124.     procedure ReadSettings;
  125.     procedure WndProc(var Message: TMessage); override;
  126.     procedure WriteSettings;
  127.   public
  128.     procedure Initialize(FromService: Boolean);
  129.     property SelectedSocket: TServerSocket read GetSelectedSocket;
  130.     property ItemIndex: Integer read GetItemIndex write SetItemIndex;
  131.   end;
  132.  
  133.   TSocketService = class(TService)
  134.   protected
  135.     procedure Start(Sender: TService; var Started: Boolean);
  136.     procedure Stop(Sender: TService; var Stopped: Boolean);
  137.   public
  138.     function GetServiceController: TServiceController; override;
  139.     constructor CreateNew(AOwner: TComponent; Dummy: Integer = 0); override;
  140.   end;
  141.  
  142. var
  143.   SocketForm: TSocketForm;
  144.   SocketService: TSocketService;
  145.  
  146. implementation
  147.  
  148. uses ScktCnst, SConnect, ActiveX, MidConst;
  149.  
  150. {$R *.DFM}
  151.  
  152. { TSocketDispatcherThread }
  153.  
  154. type
  155.   TSocketDispatcherThread = class(TServerClientThread, ISendDataBlock)
  156.   private
  157.     FRefCount: Integer;
  158.     FInterpreter: TDataBlockInterpreter;
  159.     FTransport: ITransport;
  160.     FInterceptGUID: string;
  161.     FLastActivity: TDateTime;
  162.     FTimeout: TDateTime;
  163.     FRegisteredOnly: Boolean;
  164.   protected
  165.     function CreateServerTransport: ITransport; virtual;
  166.     procedure AddClient;
  167.     procedure RemoveClient;
  168.     { IUnknown }
  169.     function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  170.     function _AddRef: Integer; stdcall;
  171.     function _Release: Integer; stdcall;
  172.     { ISendDataBlock }
  173.     function Send(const Data: IDataBlock; WaitForResult: Boolean): IDataBlock; stdcall;
  174.   public
  175.     constructor Create(CreateSuspended: Boolean; ASocket: TServerClientWinSocket;
  176.       const InterceptGUID: string; Timeout: Integer; RegisteredOnly: Boolean);
  177.     procedure ClientExecute; override;
  178.     property LastActivity: TDateTime read FLastActivity;
  179.   end;
  180.  
  181. constructor TSocketDispatcherThread.Create(CreateSuspended: Boolean;
  182.   ASocket: TServerClientWinSocket; const InterceptGUID: string; Timeout: Integer;
  183.   RegisteredOnly: Boolean);
  184. begin
  185.   FInterceptGUID := InterceptGUID;
  186.   FTimeout := EncodeTime(Timeout div 60, Timeout mod 60, 0, 0);
  187.   FLastActivity := Now;
  188.   FRegisteredOnly := RegisteredOnly;
  189.   inherited Create(CreateSuspended, ASocket);
  190. end;
  191.  
  192. function TSocketDispatcherThread.CreateServerTransport: ITransport;
  193. var
  194.   SocketTransport: TSocketTransport;
  195. begin
  196.   SocketTransport := TSocketTransport.Create;
  197.   SocketTransport.Socket := ClientSocket;
  198.   SocketTransport.InterceptGUID := FInterceptGUID;
  199.   Result := SocketTransport as ITransport;
  200. end;
  201.  
  202. procedure TSocketDispatcherThread.AddClient;
  203. begin
  204.   SocketForm.AddClient(Self);
  205. end;
  206.  
  207. procedure TSocketDispatcherThread.RemoveClient;
  208. begin
  209.   SocketForm.RemoveClient(Self);
  210. end;
  211.  
  212. { TSocketDispatcherThread.IUnknown }
  213.  
  214. function TSocketDispatcherThread.QueryInterface(const IID: TGUID; out Obj): HResult;
  215. begin
  216.   if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE;
  217. end;
  218.  
  219. function TSocketDispatcherThread._AddRef: Integer;
  220. begin
  221.   Inc(FRefCount);
  222.   Result := FRefCount;
  223. end;
  224.  
  225. function TSocketDispatcherThread._Release: Integer;
  226. begin
  227.   Dec(FRefCount);
  228.   Result := FRefCount;
  229. end;
  230.  
  231. { TSocketDispatcherThread.ISendDataBlock }
  232.  
  233. function TSocketDispatcherThread.Send(const Data: IDataBlock; WaitForResult: Boolean): IDataBlock;
  234. begin
  235.   FTransport.Send(Data);
  236.   if WaitForResult then
  237.     while True do
  238.     begin
  239.       Result := FTransport.Receive(True, 0);
  240.       if Result = nil then break;
  241.       if (Result.Signature and ResultSig) = ResultSig then
  242.         break else
  243.         FInterpreter.InterpretData(Result);
  244.     end;
  245. end;
  246.  
  247. procedure TSocketDispatcherThread.ClientExecute;
  248. var
  249.   Data: IDataBlock;
  250.   msg: TMsg;
  251.   Obj: ISendDataBlock;
  252.   Event: THandle;
  253.   WaitTime: DWord;
  254. begin
  255.   CoInitialize(nil);
  256.   try
  257.     Synchronize(AddClient);
  258.     FTransport := CreateServerTransport;
  259.     try
  260.       Event := FTransport.GetWaitEvent;
  261.       PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE);
  262.       GetInterface(ISendDataBlock, Obj);
  263.       if FRegisteredOnly then
  264.         FInterpreter := TDataBlockInterpreter.Create(Obj, SSockets) else
  265.         FInterpreter := TDataBlockInterpreter.Create(Obj, '');
  266.       try
  267.         Obj := nil;
  268.         if FTimeout = 0 then
  269.           WaitTime := INFINITE else
  270.           WaitTime := 60000;
  271.         while not Terminated and FTransport.Connected do
  272.         try
  273.           case MsgWaitForMultipleObjects(1, Event, False, WaitTime, QS_ALLEVENTS) of
  274.             WAIT_OBJECT_0:
  275.             begin
  276.               WSAResetEvent(Event);
  277.               Data := FTransport.Receive(False, 0);
  278.               if Assigned(Data) then
  279.               begin
  280.                 FLastActivity := Now;
  281.                 FInterpreter.InterpretData(Data);
  282.                 Data := nil;
  283.                 FLastActivity := Now;
  284.               end;
  285.             end;
  286.             WAIT_OBJECT_0 + 1:
  287.               while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
  288.                 DispatchMessage(msg);
  289.             WAIT_TIMEOUT:
  290.               if (FTimeout > 0) and ((Now - FLastActivity) > FTimeout) then
  291.                 FTransport.Connected := False;
  292.           end;
  293.         except
  294.           FTransport.Connected := False;
  295.         end;
  296.       finally
  297.         FInterpreter.Free;
  298.         FInterpreter := nil;
  299.       end;
  300.     finally
  301.       FTransport := nil;
  302.     end;
  303.   finally
  304.     CoUninitialize;
  305.     Synchronize(RemoveClient);
  306.   end;
  307. end;
  308.  
  309. { TSocketDispatcher }
  310.  
  311. type
  312.   TSocketDispatcher = class(TServerSocket)
  313.   private
  314.     FInterceptGUID: string;
  315.     FTimeout: Integer;
  316.     procedure GetThread(Sender: TObject; ClientSocket: TServerClientWinSocket;
  317.       var SocketThread: TServerClientThread);
  318.   public
  319.     constructor Create(AOwner: TComponent); override;
  320.     procedure ReadSettings(PortNo: Integer; Reg: TRegINIFile);
  321.     procedure WriteSettings(Reg: TRegINIFile);
  322.     property InterceptGUID: string read FInterceptGUID write FInterceptGUID;
  323.     property Timeout: Integer read FTimeout write FTimeout;
  324.   end;
  325.  
  326. constructor TSocketDispatcher.Create(AOwner: TComponent);
  327. begin
  328.   inherited Create(AOwner);
  329.   ServerType := stThreadBlocking;
  330.   OnGetThread := GetThread;
  331. end;
  332.  
  333. procedure TSocketDispatcher.GetThread(Sender: TObject;
  334.   ClientSocket: TServerClientWinSocket;
  335.   var SocketThread: TServerClientThread);
  336. begin
  337.   SocketThread := TSocketDispatcherThread.Create(False, ClientSocket,
  338.     InterceptGUID, Timeout, SocketForm.RegisteredAction.Checked);
  339. end;
  340.  
  341. procedure TSocketDispatcher.ReadSettings(PortNo: Integer; Reg: TRegINIFile);
  342. var
  343.   Section: string;
  344. begin
  345.   if PortNo = -1 then
  346.   begin
  347.     Section := csSettings;
  348.     Port := Reg.ReadInteger(Section, ckPort, 211);
  349.   end else
  350.   begin
  351.     Section := IntToStr(PortNo);
  352.     Port := PortNo;
  353.   end;
  354.   ThreadCacheSize := Reg.ReadInteger(Section, ckThreadCacheSize, 10);
  355.   FInterceptGUID := Reg.ReadString(Section, ckInterceptGUID, '');
  356.   FTimeout := Reg.ReadInteger(Section, ckTimeout, 0);
  357. end;
  358.  
  359. procedure TSocketDispatcher.WriteSettings(Reg: TRegINIFile);
  360. var
  361.   Section: string;
  362. begin
  363.   Section := IntToStr(Port);
  364.   Reg.WriteInteger(Section, ckPort, Port);
  365.   Reg.WriteInteger(Section, ckThreadCacheSize, ThreadCacheSize);
  366.   Reg.WriteString(Section, ckInterceptGUID, InterceptGUID);
  367.   Reg.WriteInteger(Section, ckTimeout, Timeout);
  368. end;
  369.  
  370. { TSocketService }
  371.  
  372. procedure ServiceController(CtrlCode: DWord); stdcall;
  373. begin
  374.   SocketService.Controller(CtrlCode);
  375. end;
  376.  
  377. function TSocketService.GetServiceController: TServiceController;
  378. begin
  379.   Result := ServiceController;
  380. end;
  381.  
  382. constructor TSocketService.CreateNew(AOwner: TComponent; Dummy: Integer);
  383. begin
  384.   inherited CreateNew(AOwner, Dummy);
  385.   AllowPause := False;
  386.   Interactive := True;
  387.   DisplayName := SApplicationName;
  388.   Name := SServiceName;
  389.   OnStart := Start;
  390.   OnStop := Stop;
  391. end;
  392.  
  393. procedure TSocketService.Start(Sender: TService; var Started: Boolean);
  394. begin
  395.   PostMessage(SocketForm.Handle, UI_INITIALIZE, 1, 0);
  396.   Started := True;
  397. end;
  398.  
  399. procedure TSocketService.Stop(Sender: TService; var Stopped: Boolean);
  400. begin
  401.   PostMessage(SocketForm.Handle, WM_QUIT, 0, 0);
  402.   Stopped := True;
  403. end;
  404.  
  405. { TSocketForm }
  406.  
  407. procedure TSocketForm.FormCreate(Sender: TObject);
  408. begin
  409.   if not LoadWinSock2 then
  410.     raise Exception.CreateRes(@SNoWinSock2);
  411.   FClosing := False;
  412.   FCurItem := -1;
  413.   FSortCol := -1;
  414. end;
  415.  
  416. procedure TSocketForm.WndProc(var Message: TMessage);
  417. begin
  418.   if Message.Msg = FTaskMessage then
  419.   begin
  420.     AddIcon;
  421.     Refresh;
  422.   end;
  423.   inherited WndProc(Message);
  424. end;
  425.  
  426. procedure TSocketForm.UpdateTimerTimer(Sender: TObject);
  427. var
  428.   Found: Boolean;
  429. begin
  430.   Found := FindWindow('Progman', nil) <> 0;
  431.   if Found <> FProgmanOpen then
  432.   begin
  433.     FProgmanOpen := Found;
  434.     if Found then AddIcon;
  435.     Refresh;
  436.   end;
  437. end;
  438.  
  439. procedure TSocketForm.CheckValues;
  440. begin
  441.   StrToInt(PortNo.Text);
  442.   StrToInt(ThreadSize.Text);
  443.   StrToInt(Timeout.Text);
  444. end;
  445.  
  446. function TSocketForm.GetItemIndex: Integer;
  447. begin
  448.   Result := FCurItem;
  449. end;
  450.  
  451. procedure TSocketForm.SetItemIndex(Value: Integer);
  452. var
  453.   Selected: Boolean;
  454. begin
  455.   if (FCurItem <> Value) then
  456.   try
  457.     if ApplyAction.Enabled then ApplyAction.Execute;
  458.   except
  459.     PortList.ItemIndex := FCurItem;
  460.     raise;
  461.   end else
  462.     Exit;
  463.   if Value = -1 then Value := 0;
  464.   PortList.ItemIndex := Value;
  465.   FCurItem := PortList.ItemIndex;
  466.   Selected := FCurItem <> -1;
  467.   if Selected then
  468.     with TSocketDispatcher(PortList.Items.Objects[FCurItem]) do
  469.     begin
  470.       PortUpDown.Position := Port;
  471.       ThreadUpDown.Position := ThreadCacheSize;
  472.       Self.InterceptGUID.Text := FInterceptGUID;
  473.       TimeoutUpDown.Position := Timeout;
  474.       ClearModifications;
  475.     end;
  476.   PortNo.Enabled := Selected;
  477.   ThreadSize.Enabled := Selected;
  478.   Timeout.Enabled := Selected;
  479.   InterceptGUID.Enabled := Selected;
  480. end;
  481.  
  482. function TSocketForm.GetSelectedSocket: TServerSocket;
  483. begin
  484.   Result := TServerSocket(PortList.Items.Objects[ItemIndex]);
  485. end;
  486.  
  487. procedure TSocketForm.UIInitialize(var Message: TMessage);
  488. begin
  489.   Initialize(Message.WParam <> 0);
  490. end;
  491.  
  492. procedure TSocketForm.Initialize(FromService: Boolean);
  493.  
  494.   function IE4Installed: Boolean;
  495.   var
  496.     RegKey: HKEY;
  497.   begin
  498.     Result := False;
  499.     if RegOpenKey(HKEY_LOCAL_MACHINE, KEY_IE, RegKey) = ERROR_SUCCESS then
  500.     try
  501.       Result := RegQueryValueEx(RegKey, 'Version', nil, nil, nil, nil) = ERROR_SUCCESS;
  502.     finally
  503.       RegCloseKey(RegKey);
  504.     end;
  505.   end;
  506.  
  507. begin
  508.   FFromService := FromService;
  509.   NT351 := (Win32MajorVersion <= 3) and (Win32Platform = VER_PLATFORM_WIN32_NT);
  510.   if NT351 then
  511.   begin
  512.     if not FromService then
  513.       raise Exception.CreateRes(@SServiceOnly);
  514.     BorderIcons := BorderIcons + [biMinimize];
  515.     BorderStyle := bsSingle;
  516.   end;
  517.   ReadSettings;
  518.   if FromService then
  519.   begin
  520.     miClose.Visible := False;
  521.     N1.Visible := False;
  522.   end;
  523.   UpdateStatus;
  524.   AddIcon;
  525.   if IE4Installed then
  526.     FTaskMessage := RegisterWindowMessage('TaskbarCreated') else
  527.     UpdateTimer.Enabled := True;
  528. end;
  529.  
  530. procedure TSocketForm.FormCloseQuery(Sender: TObject;
  531.   var CanClose: Boolean);
  532. var
  533.   TimerEnabled: Boolean;
  534. begin
  535.   TimerEnabled := UpdateTimer.Enabled;
  536.   UpdateTimer.Enabled := False;
  537.   try
  538.     CanClose := False;
  539.     if ApplyAction.Enabled then ApplyAction.Execute;
  540.     if FClosing and (not FFromService) and (ConnectionList.Items.Count > 0) then
  541.     begin
  542.       FClosing := False;
  543.       if MessageDlg(SErrClose, mtConfirmation, [mbYes, mbNo], 0) <> idYes then
  544.         Exit;
  545.     end;
  546.     WriteSettings;
  547.     CanClose := True;
  548.   finally
  549.     if TimerEnabled and (not CanClose) then
  550.       UpdateTimer.Enabled := True;
  551.   end;
  552. end;
  553.  
  554. procedure TSocketForm.FormDestroy(Sender: TObject);
  555. var
  556.   i: Integer;
  557. begin
  558.   UpdateTimer.Enabled := False;
  559.   if not NT351 then
  560.     Shell_NotifyIcon(NIM_DELETE, @FIconData);
  561.   for i := 0 to PortList.Items.Count - 1 do
  562.     PortList.Items.Objects[i].Free;
  563. end;
  564.  
  565. procedure TSocketForm.AddIcon;
  566. begin
  567.   if not NT351 then
  568.   begin
  569.     with FIconData do
  570.     begin
  571.       cbSize := SizeOf(FIconData);
  572.       Wnd := Self.Handle;
  573.       uID := $DEDB;
  574.       uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
  575.       hIcon := Forms.Application.Icon.Handle;
  576.       uCallbackMessage := WM_MIDASICON;
  577.       StrCopy(szTip, PChar(Caption));
  578.     end;
  579.     Shell_NotifyIcon(NIM_Add, @FIconData);
  580.   end;
  581. end;
  582.  
  583. procedure TSocketForm.ReadSettings;
  584. var
  585.   Reg: TRegINIFile;
  586.  
  587.   procedure CreateItem(ID: Integer);
  588.   var
  589.     SH: TSocketDispatcher;
  590.   begin
  591.     SH := TSocketDispatcher.Create(nil);
  592.     SH.ReadSettings(ID, Reg);
  593.     PortList.Items.AddObject(IntToStr(SH.Port), SH);
  594.     try
  595.       SH.Open;
  596.     except
  597.       on E: Exception do
  598.         raise Exception.CreateResFmt(@SOpenError, [SH.Port, E.Message]);
  599.     end;
  600.   end;
  601.  
  602. var
  603.   Sections: TStringList;
  604.   i: Integer;
  605. begin
  606.   Reg := TRegINIFile.Create('');
  607.   try
  608.     Reg.RootKey := HKEY_LOCAL_MACHINE;
  609.     Reg.OpenKey(KEY_SOCKETSERVER, True);
  610.     Sections := TStringList.Create;
  611.     try
  612.       Reg.ReadSections(Sections);
  613.       if Sections.Count > 1 then
  614.       begin
  615.         for i := 0 to Sections.Count - 1 do
  616.           if CompareText(Sections[i], csSettings) <> 0 then
  617.             CreateItem(StrToInt(Sections[i]));
  618.       end else
  619.         CreateItem(-1);
  620.       ItemIndex := 0;
  621.       ShowHostAction.Checked := Reg.ReadBool(csSettings, ckShowHost, False);
  622.       RegisteredAction.Checked := Reg.ReadBool(csSettings, ckRegistered, True);
  623.     finally
  624.       Sections.Free;
  625.     end;
  626.   finally
  627.     Reg.Free;
  628.   end;
  629. end;
  630.  
  631. procedure TSocketForm.WriteSettings;
  632. var
  633.   Reg: TRegINIFile;
  634.   Sections: TStringList;
  635.   i: Integer;
  636. begin
  637.   Reg := TRegINIFile.Create('');
  638.   try
  639.     Reg.RootKey := HKEY_LOCAL_MACHINE;
  640.     Reg.OpenKey(KEY_SOCKETSERVER, True);
  641.     Sections := TStringList.Create;
  642.     try
  643.       Reg.ReadSections(Sections);
  644.       for i := 0 to Sections.Count - 1 do
  645.         TRegistry(Reg).DeleteKey(Sections[i]);
  646.     finally
  647.       Sections.Free;
  648.     end;
  649.     for i := 0 to PortList.Items.Count - 1 do
  650.       TSocketDispatcher(PortList.Items.Objects[i]).WriteSettings(Reg);
  651.     Reg.WriteBool(csSettings, ckShowHost, ShowHostAction.Checked);
  652.     Reg.WriteBool(csSettings, ckRegistered, RegisteredAction.Checked);
  653.   finally
  654.     Reg.Free;
  655.   end;
  656. end;
  657.  
  658. procedure TSocketForm.miCloseClick(Sender: TObject);
  659. begin
  660.   FClosing := True;
  661.   Close;
  662. end;
  663.  
  664. procedure TSocketForm.WMMIDASIcon(var Message: TMessage);
  665. var
  666.   pt: TPoint;
  667. begin
  668.   case Message.LParam of
  669.     WM_RBUTTONUP:
  670.     begin
  671.       if not Visible then
  672.       begin
  673.         SetForegroundWindow(Handle);
  674.         GetCursorPos(pt);
  675.         PopupMenu.Popup(pt.x, pt.y);
  676.       end else
  677.         SetForegroundWindow(Handle);
  678.     end;
  679.     WM_LBUTTONDBLCLK:
  680.       if Visible then
  681.         SetForegroundWindow(Handle) else
  682.         miPropertiesClick(nil);
  683.   end;
  684. end;
  685.  
  686. procedure TSocketForm.miPropertiesClick(Sender: TObject);
  687. begin
  688.   ShowModal;
  689. end;
  690.  
  691. procedure TSocketForm.FormShow(Sender: TObject);
  692. begin
  693.   Pages.ActivePage := Pages.Pages[0];
  694. end;
  695.  
  696. procedure TSocketForm.UpdateStatus;
  697. begin
  698.   UserStatus.SimpleText := Format(SStatusLine,[ConnectionList.Items.Count]);
  699. end;
  700.  
  701. procedure TSocketForm.AddClient(Thread: TServerClientThread);
  702. var
  703.   Item: TListItem;
  704. begin
  705.   Item := ConnectionList.Items.Add;
  706.   Item.Caption := IntToStr(Thread.ClientSocket.LocalPort);
  707.   Item.SubItems.Add(Thread.ClientSocket.RemoteAddress);
  708.   if ShowHostAction.Checked then
  709.   begin
  710.     Item.SubItems.Add(Thread.ClientSocket.RemoteHost);
  711.     if Item.SubItems[1] = '' then Item.SubItems[1] := SHostUnknown;
  712.   end else
  713.     Item.SubItems.Add(SNotShown);
  714.   if Thread is TSocketDispatcherThread then
  715.     Item.SubItems.Add(DateTimeToStr(TSocketDispatcherThread(Thread).LastActivity));
  716.   Item.Data := Pointer(Thread);
  717.   UpdateStatus;
  718. end;
  719.  
  720. procedure TSocketForm.RemoveClient(Thread: TServerClientThread);
  721. var
  722.   Item: TListItem;
  723. begin
  724.   Item := ConnectionList.FindData(0, Thread, True, False);
  725.   if Assigned(Item) then Item.Free;
  726.   UpdateStatus;
  727. end;
  728.  
  729. procedure TSocketForm.miDisconnectClick(Sender: TObject);
  730. var
  731.   i: Integer;
  732. begin
  733.   if MessageDlg(SQueryDisconnect, mtConfirmation, [mbYes, mbNo], 0) = mrNo then
  734.     Exit;
  735.   with SelectedSocket.Socket do
  736.   begin
  737.     Lock;
  738.     try
  739.       for i := 0 to ConnectionList.Items.Count - 1 do
  740.         with ConnectionList.Items[i] do
  741.           if Selected then
  742.             TServerClientThread(Data).ClientSocket.Close;
  743.     finally
  744.       Unlock;
  745.     end;
  746.   end;
  747. end;
  748.  
  749. procedure TSocketForm.miExitClick(Sender: TObject);
  750. begin
  751.   CheckValues;
  752.   ModalResult := mrOK;
  753. end;
  754.  
  755. procedure TSocketForm.ApplyActionExecute(Sender: TObject);
  756. begin
  757.   with TSocketDispatcher(SelectedSocket) do
  758.   begin
  759.     if Socket.ActiveConnections > 0 then
  760.       if MessageDlg(SErrChangeSettings, mtConfirmation, [mbYes, mbNo], 0) = idNo then
  761.         Exit;
  762.     Close;
  763.     Port := StrToInt(PortNo.Text);
  764.     PortList.Items[ItemIndex] := PortNo.Text;
  765.     ThreadCacheSize := StrToInt(ThreadSize.Text);
  766.     InterceptGUID := Self.InterceptGUID.Text;
  767.     Timeout := StrToInt(Self.Timeout.Text);
  768.     Open;
  769.   end;
  770.   ClearModifications;
  771. end;
  772.  
  773. procedure TSocketForm.ApplyActionUpdate(Sender: TObject);
  774. begin
  775.   ApplyAction.Enabled := PortNo.Modified or ThreadSize.Modified or
  776.     Timeout.Modified or InterceptGUID.Modified;
  777. end;
  778.  
  779. procedure TSocketForm.ClearModifications;
  780. begin
  781.   PortNo.Modified  := False;
  782.   ThreadSize.Modified := False;
  783.   Timeout.Modified := False;
  784.   InterceptGUID.Modified := False;
  785. end;
  786.  
  787. procedure TSocketForm.DisconnectActionUpdate(Sender: TObject);
  788. begin
  789.   DisconnectAction.Enabled := ConnectionList.SelCount > 0;
  790. end;
  791.  
  792. procedure TSocketForm.ShowHostActionExecute(Sender: TObject);
  793. var
  794.   i: Integer;
  795.   Item: TListItem;
  796. begin
  797.   ShowHostAction.Checked := not ShowHostAction.Checked;
  798.   ConnectionList.Items.BeginUpdate;
  799.   try
  800.     for i := 0 to ConnectionList.Items.Count - 1 do
  801.     begin
  802.       Item := ConnectionList.Items[i];
  803.       if ShowHostAction.Checked then
  804.       begin
  805.         Item.SubItems[1] := TServerClientThread(Item.Data).ClientSocket.RemoteHost;
  806.         if Item.SubItems[1] = '' then Item.SubItems[1] := SHostUnknown;
  807.       end else
  808.         Item.SubItems[1] := SNotShown;
  809.     end;
  810.   finally
  811.     ConnectionList.Items.EndUpdate;
  812.   end;
  813. end;
  814.  
  815. procedure TSocketForm.miAddClick(Sender: TObject);
  816. var
  817.   SD: TSocketDispatcher;
  818.   Idx: Integer;
  819. begin
  820.   CheckValues;
  821.   SD := TSocketDispatcher.Create(nil);
  822.   SD.Port := PortUpDown.Position + 1;
  823.   PortUpDown.Position := SD.Port;
  824.   Idx := PortList.Items.AddObject(PortNo.Text,SD);
  825.   PortNo.Modified := True;
  826.   ItemIndex := Idx;
  827.   Pages.ActivePage := Pages.Pages[0];
  828.   PortNo.SetFocus;
  829. end;
  830.  
  831. procedure TSocketForm.RemovePortActionUpdate(Sender: TObject);
  832. begin
  833.   RemovePortAction.Enabled := (PortList.Items.Count > 1) and (ItemIndex <> -1);
  834. end;
  835.  
  836. procedure TSocketForm.RemovePortActionExecute(Sender: TObject);
  837. begin
  838.   CheckValues;
  839.   PortList.Items.Objects[ItemIndex].Free;
  840.   PortList.Items.Delete(ItemIndex);
  841.   FCurItem := -1;
  842.   ItemIndex := 0;
  843. end;
  844.  
  845. procedure TSocketForm.UpDownClick(Sender: TObject; Button: TUDBtnType);
  846. begin
  847.   ((Sender as TUpDown).Associate as TEdit).Modified := True;
  848. end;
  849.  
  850. procedure TSocketForm.PortListClick(Sender: TObject);
  851. begin
  852.   ItemIndex := PortList.ItemIndex;
  853. end;
  854.  
  855. procedure TSocketForm.ConnectionListCompare(Sender: TObject; Item1,
  856.   Item2: TListItem; Data: Integer; var Compare: Integer);
  857. begin
  858.   if Data = -1 then
  859.     Compare := AnsiCompareText(Item1.Caption, Item2.Caption) else
  860.     Compare := AnsiCompareText(Item1.SubItems[Data], Item2.SubItems[Data]);
  861. end;
  862.  
  863. procedure TSocketForm.ConnectionListColumnClick(Sender: TObject;
  864.   Column: TListColumn);
  865. begin
  866.   FSortCol := Column.Index - 1;
  867.   ConnectionList.CustomSort(nil, FSortCol);
  868. end;
  869.  
  870. procedure TSocketForm.IntegerExit(Sender: TObject);
  871. begin
  872.   try
  873.     StrToInt(PortNo.Text);
  874.   except
  875.     ActiveControl := PortNo;
  876.     raise;
  877.   end;
  878. end;
  879.  
  880. procedure TSocketForm.RegisteredActionExecute(Sender: TObject);
  881. begin
  882.   RegisteredAction.Checked := not RegisteredAction.Checked;
  883.   ShowMessage(SNotUntilRestart);
  884. end;
  885.  
  886. end.
  887.