Indy10 即時通信Demo

最近閒來無事,從新學習了Indy10,順手寫了一段即時通信代碼。與上次寫的筆記有不一樣之處,但差異不大。windows

未研究過TCP打洞技術,因此下面的代碼採用的是  客戶端--服務器--客戶端  模式,也就是服務器端轉發消息的模式。服務器

 客戶端模仿了QQ,能夠在屏幕四周停靠自動隱藏dom

本文也演示了在線程中操做VCL的兩張方法:ide

1:向主線程發送消息函數

2:在線程中使用臨界區學習

program Server;

uses
  Forms,
  UntMain in 'UntMain.pas' {Form2},
  Unit2 in 'Unit2.pas',
  Unit4 in 'Unit4.pas';

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm2, Form2);
  Application.Run;
end.

服務器端:加密

unit UntMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdContext, IdScheduler, IdSchedulerOfThread, IdSchedulerOfThreadPool,
  IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPServer, ImgList,
  CoolTrayIcon, ExtCtrls, RzPanel, Unit2, IdGlobal, StdCtrls, RzLstBox,
  IdSchedulerOfThreadDefault, RzStatus, RzButton, RzEdit,SyncObjs;

type
  TForm2 = class(TForm)
    CoolTrayIcon1: TCoolTrayIcon;
    ImageList1: TImageList;
    IdTCPServer1: TIdTCPServer;
    RzStatusBar1: TRzStatusBar;
    RzListBox1: TRzListBox;
    IdSchedulerOfThreadDefault1: TIdSchedulerOfThreadDefault;
    Button1: TButton;
    RzStatusPane1: TRzStatusPane;
    RzStatusPane2: TRzStatusPane;
    RzMemo1: TRzMemo;
    RzButton1: TRzButton;
    RzMemo2: TRzMemo;
    Timer1: TTimer;
    procedure IdTCPServer1Execute(AContext: TIdContext);
    procedure CustomMessage(var message: TMessage); message CustMsg;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
    procedure IdTCPServer1Disconnect(AContext: TIdContext);
    procedure RzButton1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  private
    { Private declarations }

  public
    { Public declarations }
  end;
  //TIdServerContext 類繼承自 TIdContext類
  //IdCustomTCPServer 單元 第295行
  TMyClass = class(TIdServerContext)
    CltInfo: TCltInfo;
  end;

var
  Form2: TForm2;
  CriticalSection:TCriticalSection;
implementation

{$R *.dfm}
uses
  Unit4;
procedure TForm2.Button1Click(Sender: TObject);
begin
  IdTCPServer1.Active := True;
  if IdTCPServer1.Active then
  begin
    RzMemo1.Lines.Add('服務器開啓成功...');
  end;
end;

procedure TForm2.CustomMessage(var message: TMessage);
var
  i,n: Integer;
  ss,ip,Nc,sNc: string;
  buf:TDataPack;
  list:Tlist;
  FContext:TIdContext;
begin
  FContext := TMyClass(message.LParam);
  case message.WParam of
    CltConnect:
    begin
      ss:='';
      Nc := TMyClass(FContext).CltInfo.CltName;
      ip:= TMyClass(FContext).CltInfo.CltIP;
      RzListBox1.Items.Add(Nc);
      RzMemo2.Lines.Add('【客戶:】' + Nc + ' (' + ip +') 登錄'+'---'+DateTimeToStr(Now));

      for i := 0 to RzListBox1.Items.Count - 1 do // 發送連線客戶端列表
        ss:=ss+form2.RzListBox1.ItemCaption(i)+'|';
      sNc :=Encrystrings(ss);
      FillChar(buf, SizeOf(TDataPack), '');
      buf.Command := CltList;
      StrCopy(@buf.Data, PChar(sNc));
      List := form2.IdTCPServer1.Contexts.LockList;
      n:= List.Count;
      try
        for I := 0 to n-1 do
        begin
          try

            TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
          except
            //
          end;
        end;
      finally
        form2.IdTCPServer1.Contexts.UnlockList;
      end;
    end;

    CltDisconnect:
      begin
        for i := 0 to RzListBox1.Items.Count - 1 do
        begin
          if RzListBox1.ItemCaption(i) = TMyClass(FContext).CltInfo.CltName  then
          begin

            RzListBox1.Items.Delete(i);
            RzMemo2.Lines.Add('【用戶:】 '+ string(TMyClass(FContext).CltInfo.CltName) +'  離開---'+DateTimeToStr(Now));
            Break;
          end;
        end;

        FillChar(buf, SizeOf(TDataPack), '');
        ss := '';

        for i := 0 to RzListBox1.Items.Count - 1 do // 發送連線客戶端列表
          ss := ss + Form2.RzListBox1.ItemCaption(i) + '|';
        ss:=Encrystrings(ss);
        buf.Command := CltList;
        StrCopy(@buf.Data, PChar(ss));
        list:= IdTCPServer1.Contexts.LockList;
        n:= List.Count;
        try
          for i := 0 to n - 1 do
          try
            TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
          except
            //
          end;
        finally
          IdTCPServer1.Contexts.UnlockList;
        end;
      end;
    CltSendMessage:
      begin

      end;
  end;
end;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin

  RzListBox1.Clear;
  IdTCPServer1.Active := False;
end;

procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var
  List:TList;
  i,n:Integer;
  LContext: TMyClass;
  buf:TDataPack;
begin
  //當有客戶端還沒有斷開鏈接時,服務器主動斷開鏈接會致使異常
  //因此,在服務器端退出以前,檢查時候有客戶端還沒有斷開
  //如有,通知客戶端主動斷開鏈接
  List:= IdTCPServer1.Contexts.LockList;
  n:= List.Count;
  try
    if n >0 then
    begin
      CanClose := False;
      FillChar(buf,SizeOf(TdataPack),'');
      buf.Command := SrvCloseQuery;
      for I := 0 to n - 1 do
      begin
        LContext := TMyClass(List.Items[i]);
        LContext.Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
      end;
    end else CanClose := True;
  finally
    IdTCPServer1.Contexts.UnlockList;
  end;
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  //在IdCustomTCPServer 單元第302行,定義了類的指針:
  //TIdServerContextClass = class of TIdServerContext;
  //AContext不肯定以 TIdServerContext類建立,因此定義了一個類的指針TIdServerContextClass,
  //AContext將以TIdServerContextClass指針所指向的類來建立,從新賦值指針,將以新類建立實例

  //這裏從新賦值AContext 新類,當客戶端鏈接後,AContext將以新類TMyClass的實例創捷
  //AContext 被建立後,將包含TMyClass類的新屬性 TCltInfo
  //詳見IdCustomTCPServer 單元第956行
  //若是不從新賦值AContext新類,AContext 在IdCustomTCPServer初始化時(TIdCustomTCPServer.InitComponent方法),
  //以默認類TIdServerContext建立
  //詳見 IdCustomTCPServer 單元第812行
  //這裏咱們須要給AContext 添加新屬性 TCltInfo 用來保存客戶端信息
  //因此,以TIdServerContext 爲基類,咱們擴展出  TMyClass 子類
  //每一個客戶端鏈接後,AContext即被建立,並把每一個AContext地址(對象指針)保存在IdTCPServer.Contexts屬性中
  //當服務器端須要與某個客戶端回話時,能夠遍歷Contexts屬性
  IdTCPServer1.ContextClass := TMyClass;
  IdTCPServer1.Active := True;
  if IdTCPServer1.Active then
  begin
    RzMemo1.Lines.Add('服務器開啓成功...('+ DateTimeToStr(Now) + ')');
  end;
  CriticalSection:=TCriticalSection.Create;
end;

procedure TForm2.FormDestroy(Sender: TObject);
begin
  CriticalSection.Free;
end;

procedure TForm2.IdTCPServer1Disconnect(AContext: TIdContext);
begin
  SendMessage(Handle,CustMsg,CltDisconnect,LongInt(AContext));
end;

procedure TForm2.IdTCPServer1Execute(AContext: TIdContext);
var
  BByte: TIdBytes;
  buf: TDataPack;
  i,n: Integer;
  s,ss,ds,nr,Nc,ip:string;
  List:Tlist;
begin
  FillChar(buf, SizeOf(TDataPack), '');
  AContext.Connection.IOHandler.ReadBytes(BByte, SizeOf(TDataPack), False);
  BytesToRaw(BByte, buf, SizeOf(TDataPack));
//---------------------------------------------------------------------------------------
  case buf.Command of
    CltConnect:
      begin
        ss:='';
        s:= string(buf.CltInfo.CltName);
        Nc :=Uncrystrings(s);
        ip:=AContext.Binding.PeerIP;
        StrCopy(@TMyClass(AContext).CltInfo.CltName,PChar(Nc)) ;
        StrCopy(@TMyClass(AContext).CltInfo.CltIP,PChar(ip));
        Nc :=Uncrystrings(s);
        for i := 0 to RzListBox1.Items.Count - 1 do
        begin
          if RzListBox1.Items[i]=Nc then
          begin
            buf.Command := CltDisconnect;
            AContext.Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
            Exit;
          end;
        end;
        SendMessage(Handle,CustMsg,CltConnect,LongInt(AContext));
      end;
//------------------------------------------------------------------------------------------------
    CltSendMessage:
      begin
        s:= Uncrystrings(string(buf.CltInfo.CltName));
        ds:=Uncrystrings(string(buf.DstInfo.CltName));
        nr:=Uncrystrings(string(buf.Data)) +#13+#10;
        List := form2.IdTCPServer1.Contexts.LockList;
        n:= List.Count;
        try
          for i := 0 to n - 1 do
          begin
            if TMyClass(List.Items[i]).CltInfo.CltName = ds then
            begin
              try
                CriticalSection.Enter;
                try
                  TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
                  RzMemo1.Lines.Add(s + '對 '+ds + ' 說:'+ nr);
                finally
                  CriticalSection.Leave;
                end;
              except
                buf.Command := SrvMessage;
                AContext.Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
              end;
              Exit;
            end;
          end;
        finally
          form2.IdTCPServer1.Contexts.UnlockList;
        end;
      end;
//--------------------------------------------------------------------------------------------------------
    CltTimer :
    begin
      AContext.Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
    end;
//---------------------------------------------------------------------------------------------------------
    CltClear :
    begin
      s:= Uncrystrings(string(buf.CltInfo.CltName));
      ds:=Uncrystrings(string(buf.DstInfo.CltName));
      List := form2.IdTCPServer1.Contexts.LockList;
      n:= List.Count;
      try
        for i := 0 to n - 1 do
        begin
          if TMyClass(List.Items[i]).CltInfo.CltName = ds then
          begin
            try
              CriticalSection.Enter;
              try
                TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
                RzMemo1.Lines.Add(s + ' 清除了 '+ds + ' 的屏幕'+#13+#10);
              finally
                CriticalSection.Leave;
              end;
            except
              //
            end;
            Exit;
          end;
        end;
      finally
        form2.IdTCPServer1.Contexts.UnlockList;
      end;
    end;
//-------------------------------------------------------------------------------------------------------
    CltLockSrc:
    begin
      s:= Uncrystrings(string(buf.CltInfo.CltName));
      List := form2.IdTCPServer1.Contexts.LockList;
      n:= List.Count;
      try
        for i := 0 to n - 1 do
        begin
          if TMyClass(List.Items[i]).CltInfo.CltName <> s then
          begin
            try
              CriticalSection.Enter;
              try
                TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
              finally
                CriticalSection.Leave;
              end;
            except
              //
            end;
          end;
        end;
      finally
        form2.IdTCPServer1.Contexts.UnlockList;
      end;
      RzMemo1.Lines.Add(s + ' 鎖定了屏幕 '+#13+#10);
    end;
//-------------------------------------------------------------------------------------------------------
    CltUnlockSrc :
    begin
      s:= Uncrystrings(string(buf.CltInfo.CltName));
      List := form2.IdTCPServer1.Contexts.LockList;
      n:= List.Count;
      try
        for i := 0 to n - 1 do
        begin
          if TMyClass(List.Items[i]).CltInfo.CltName <> s then
          begin
            try
              TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));

            except
              //
            end;
          end;
        end;
      finally
        form2.IdTCPServer1.Contexts.UnlockList;
      end;
      RzMemo1.Lines.Add(s + ' 解鎖了屏幕 '+#13+#10);
    end;
//---------------------------------------------------------------------------------------------------------------
    CltMessage :
    begin
      ds:=Uncrystrings(string(buf.DstInfo.CltName));
      List := form2.IdTCPServer1.Contexts.LockList;
      n:= List.Count;
      try
      for i := 0 to n - 1 do
      begin
        if TMyClass(List.Items[i]).CltInfo.CltName = ds then
        begin
          try
            TMyClass(List.Items[i]).Connection.IOHandler.Write(RawToBytes(buf, SizeOf(TDataPack)), SizeOf(TDataPack));
          except
            //
          end;
          Exit;
        end;
      end;
      finally
        form2.IdTCPServer1.Contexts.UnlockList;
      end;
    end;
//-----------------------------------------------------------------------------------------------------------------
  end;
end;

procedure TForm2.RzButton1Click(Sender: TObject);
begin
  RzMemo1.Clear;
end;

end.

  客戶端線程

program Project3;

uses
  Forms,
  windows,
  Unit3 in 'Unit3.pas' {Form3},
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas',
  Unit4 in 'Unit4.pas';

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := False ;
  Application.CreateForm(TForm3, Form3);
  SetWindowLong(Application.Handle,GWL_EXSTYLE,WS_EX_TOOLWINDOW);

  Application.Run;
end.

  

unit Unit3;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, RzLstBox, ExtCtrls, ShellAPI, ImgList, RzTray, IdGlobal,
  Unit2,Clipbrd,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, RzButton,
  RzRadChk, RzPanel, Mask, RzEdit, RzLabel, ComCtrls, Menus, RzBHints, RzSplit,
  RzAnimtr, IdZLibCompressorBase, IdCompressorZLib,RxRichEd, RzListVw,Buttons,
  RzSpnEdt ;

type
  TForm3 = class(TForm)
    RzListBox1: TRzListBox;
    Timer1: TTimer;
    RzTrayIcon1: TRzTrayIcon;
    ImageList1: TImageList;
    IdTCPClient1: TIdTCPClient;
    RzCheckBox1: TRzCheckBox;
    RzPanel1: TRzPanel;
    RzPanel2: TRzPanel;
    RzMemo2: TRzMemo;
    RzLabel1: TRzLabel;
    RzEdit1: TRzEdit;
    RzButton2: TRzButton;
    RzLabel2: TRzLabel;
    RzEdit2: TRzEdit;
    Timer2: TTimer;
    PopupMenu1: TPopupMenu;
    N1: TMenuItem;
    RzButton3: TRzButton;
    BalloonHint1: TBalloonHint;
    RzLabel5: TRzLabel;
    RzEdit3: TRzEdit;
    RzSplitter1: TRzSplitter;
    RzSplitter2: TRzSplitter;
    RzAnimator1: TRzAnimator;
    ImageList2: TImageList;
    RzToolButton1: TRzToolButton;
    PopupMenu2: TPopupMenu;
    N2: TMenuItem;
    N3: TMenuItem;
    N4: TMenuItem;
    ImageList3: TImageList;
    RzButton4: TRzButton;
    RzButton5: TRzButton;
    RxRichEdit1: TRxRichEdit;
    LabeledEdit1: TLabeledEdit;
    RzPanel3: TRzPanel;
    Image01: TImage;
    Image02: TImage;
    Image03: TImage;
    Image04: TImage;
    Image05: TImage;
    Image06: TImage;
    Image07: TImage;
    Image08: TImage;
    Image09: TImage;
    Image10: TImage;
    Image11: TImage;
    Image12: TImage;
    Image13: TImage;
    Image14: TImage;
    Image15: TImage;
    Image16: TImage;
    Image17: TImage;
    Image18: TImage;
    Image19: TImage;
    Image20: TImage;
    Image21: TImage;
    Image22: TImage;
    Image23: TImage;
    Image24: TImage;
    Image25: TImage;
    Image26: TImage;
    Image27: TImage;
    Image28: TImage;
    Image29: TImage;
    Image30: TImage;
    Image31: TImage;
    Image32: TImage;
    Image33: TImage;
    Image34: TImage;
    Image35: TImage;
    Image36: TImage;
    Image37: TImage;
    Image38: TImage;
    Image39: TImage;
    Image40: TImage;
    Image41: TImage;
    Image42: TImage;
    Image43: TImage;
    Image44: TImage;
    Button1: TButton;
    RzButton1: TRzButton;
    ScrollBox1: TScrollBox;
    Image1: TImage;
    Image45: TImage;
    Image46: TImage;
    Image47: TImage;
    Image48: TImage;
    Image49: TImage;
    Image50: TImage;
    Image51: TImage;
    Timer3: TTimer;
    Image2: TImage;
    FontDialog1: TFontDialog;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure WMMOVING(var Msg: TMessage); message WM_MOVING;
    procedure wmsizing(var Msg: TMessage); message WM_SIZING;
    procedure RevCustMsg(var Msg:TMessage);message CustMsg;
    procedure SetBarHeight;
    procedure RzListBox1DblClick(Sender: TObject);
    procedure RzCheckBox1Click(Sender: TObject);
    procedure IdTCPClient1Connected(Sender: TObject);
    procedure IdTCPClient1Disconnected(Sender: TObject);
    procedure RzButton1Click(Sender: TObject);
    procedure RzButton2Click(Sender: TObject);
    procedure RzMemo2KeyPress(Sender: TObject; var Key: Char);
    procedure Timer2Timer(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure RzTrayIcon1RestoreApp(Sender: TObject);
    procedure RzTrayIcon1MinimizeApp(Sender: TObject);
    procedure RzMemo2MouseEnter(Sender: TObject);
    procedure FormMouseEnter(Sender: TObject);
    function MousePosion:Boolean;
    procedure RzListBox1MouseEnter(Sender: TObject);
    procedure N1Click(Sender: TObject);
    procedure RzButton3Click(Sender: TObject);
    procedure LabeledEdit1KeyPress(Sender: TObject; var Key: Char);
    procedure RzEdit3KeyPress(Sender: TObject; var Key: Char);
    procedure RzEdit1KeyPress(Sender: TObject; var Key: Char);
    procedure PopupMenu1Popup(Sender: TObject);
    procedure N4Click(Sender: TObject);
    procedure RzButton4Click(Sender: TObject);
    procedure RzButton5Click(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure RxRichEdit1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure Image01Click(Sender: TObject);
    procedure RzSpinButtons1DownLeftClick(Sender: TObject);
    procedure RzSpinButtons1UpRightClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure RxRichEdit1URLClick(Sender: TObject; const URLText: string;
      Button: TMouseButton);
    procedure Image1Click(Sender: TObject);
    function  MouseInScrollBox:Boolean;
    procedure Timer3Timer(Sender: TObject);
    procedure Image2Click(Sender: TObject);
  private
    { Private declarations }
    FAnchors: TAnchors;
  public
    { Public declarations }
  end;

  TRevDataThread = class(TThread)
  private
    buf: TDataPack;
  protected
    procedure Execute; override;
    procedure ShowMsg;
    procedure AddCltList;
    procedure DoDiscnt;
    procedure ClearScr;
    procedure AddMessage;
    procedure CltMessageIn;
    procedure DoSrvMessage;
    procedure DoSrvCloseQuery;
  end;
  // HidePosKind = (hpTop, hpLeft, hpBottom, hpRight);
  // THidePos = set of HidePosKind;

var
  Form3: TForm3;
  Lst_Height: Integer; // 記錄窗體隱藏前的高度
  Lst_Width: Integer; // 記錄窗體隱藏前的寬度
  Rec_Position: Boolean; // 是否啓動窗體寬高記錄標誌
  Cur_Top, Cur_Bottom: Integer; // 隱藏後窗體的頂端和底部位置
  RevDataThread:TRevDataThread;
  BoolEnable:Boolean;
implementation

uses Math, types, Unit1,StrUtils,Unit4;
{$R *.dfm}

procedure TForm3.WMMOVING(var Msg: TMessage);
begin
  inherited;
  with PRect(Msg.LParam)^ do
  begin
    if (akLeft in FAnchors) or (akRight in FAnchors) then
    begin
      if (Left > 0) and (Right < Screen.Width) then
      begin
        if Rec_Position then
        begin
          Bottom := top + Lst_Height;
          Right := Left + Lst_Width;
          Height := Lst_Height;
          Width := Lst_Width;
        end;
      end
      else
      begin
        SetBarHeight;
        top := Cur_Top;
        Bottom := Cur_Bottom;
        exit;
      end;
    end;
    Left := Min(Max(0, Left), Screen.Width - Width);
    top := Min(Max(0, top), Screen.Height - Height);
    Right := Min(Max(Width, Right), Screen.Width);
    Bottom := Min(Max(Height, Bottom), Screen.Height);
    if not Rec_Position then
    begin
      Lst_Height := Form3.Height;
      Lst_Width := Form3.Width;
    end;
    FAnchors := [];
    if Left = 0 then
      Include(FAnchors, akLeft);
    if Right = Screen.Width then
      Include(FAnchors, akRight);
    if top = 0 then
      Include(FAnchors, akTop);
    if Bottom = Screen.Height then
      Include(FAnchors, akBottom);
    Timer1.Enabled := FAnchors <> [];
    if (akLeft in FAnchors) or (akRight in FAnchors) then
    begin
      Rec_Position := True;
      SetBarHeight;
      top := Cur_Top;
      Bottom := Cur_Bottom;
    end
    else
      Rec_Position := False;
    Timer1.Enabled := FAnchors <> [];

  end;
end;

procedure TForm3.Button1Click(Sender: TObject);
var
  c:TComponent;
  s:string;
begin
  s:='01';
  c:= FindComponent('Image'+s);
            Clipboard.Assign(TImage(c).Picture);
            RxRichEdit1.PasteFromClipboard;
end;

procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if Assigned(RevDataThread) then FreeAndNil(RevDataThread);
  IdTCPClient1.Disconnect;
end;

procedure TForm3.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := False;
  RzButton3.Click;
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  Timer1.Enabled := False;
  Timer1.Interval := 200;
  //FormStyle := fsStayOnTop;
  BoolEnable:= False;
  RzListBox1.Clear;
  UnLcokTimes :=0;
  LockStatus := False;
  RxRichEdit1.Paragraph.LineSpacingRule:=lsSpecified;
  RxRichEdit1.Paragraph.LineSpacing:=20;
  ScrollBox1.VertScrollBar.Position :=0;
end;

procedure TForm3.FormMouseEnter(Sender: TObject);
begin
  RzTrayIcon1.Animate := False;
  RzTrayIcon1.IconIndex := 0;
end;

procedure TForm3.Timer1Timer(Sender: TObject);
const
  cOffset = 2;
begin
  if MousePosion then
  begin
    if akLeft in FAnchors then
      Left := 0;
    if akTop in FAnchors then
      top := 0;
    if akRight in FAnchors then
      Left := Screen.Width - Width;
    if akBottom in FAnchors then
      top := Screen.Height - Height;
  end
  else
  begin
    if akLeft in FAnchors then
    begin
      Left := -Width + cOffset;
      SetBarHeight;
      top := Cur_Top;
      Height := Cur_Bottom;
    end;
    if akTop in FAnchors then
      top := -Height + cOffset;
    if akRight in FAnchors then
    begin
      Left := Screen.Width - cOffset;
      SetBarHeight;
      top := Cur_Top;
      Height := Cur_Bottom;
    end;
    if akBottom in FAnchors then
      top := Screen.Height - cOffset;
  end;

end;

procedure TForm3.Timer2Timer(Sender: TObject);
var
  buf:TDataPack;
  bbyte:TIdBytes;
begin
  FillChar(buf,SizeOf(TDataPack),'');
  buf.Command := CltTimer;
  BByte := RawToBytes(buf, SizeOf(TDataPack));
  try
    IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
  except
    Timer2.Enabled := False;
    RzAnimator1.Animate := False;
    RzAnimator1.ImageIndex :=1;
    ShowMessage('與服務器斷開鏈接');
  end;
end;

procedure TForm3.Timer3Timer(Sender: TObject);
begin
  if not MouseInScrollBox  then
  begin
    if ScrollBox1.Visible  then ScrollBox1.Visible := False;
  end;
  Timer3.Enabled := ScrollBox1.Visible;
end;

procedure TForm3.IdTCPClient1Connected(Sender: TObject);
//var
//  BByte: TIdBytes;
//  buf: TDataPack;
begin
//  FillChar(buf, SizeOf(TDataPack), '');
//  buf.Command := CltConnect;
//  buf.CltInfo.CltName := 'ZZPC';
//  BByte := RawToBytes(buf, SizeOf(TDataPack));
//  IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
//  if Assigned(RevDataThread)  then RevDataThread.Terminate;

end;

procedure TForm3.IdTCPClient1Disconnected(Sender: TObject);
begin
  if Assigned(RevDataThread)  then RevDataThread.Terminate;
  RzListBox1.Items.Clear;
  RzEdit2.ReadOnly := False;
  RzToolButton1.Enabled := False;
  RzButton4.Enabled := False;
  RzCheckBox1.Checked := False;
end;


procedure TForm3.Image01Click(Sender: TObject);
var
  s:String;
begin
  s:=RightStr(TImage(Sender).Name,2);
  RzMemo2.Text := '['+s+']';
  ScrollBox1.Visible := False;
  RzToolButton1.Click;
end;

procedure TForm3.Image1Click(Sender: TObject);
begin
  ScrollBox1.Visible := not ScrollBox1.Visible;
  Timer3.Enabled := ScrollBox1.Visible;
end;

procedure TForm3.Image2Click(Sender: TObject);
begin
  if FontDialog1.Execute then  RxRichEdit1.Font := FontDialog1.Font;

end;

procedure TForm3.LabeledEdit1KeyPress(Sender: TObject; var Key: Char);
begin
  if ((Key = #13) and (((hi(GetKeyState(VK_CONTROL))) and $80) <> $80))  then
  begin
    Key :=#0;
    RzButton3.Click;
  end;
end;

function TForm3.MouseInScrollBox: Boolean;
begin
  Result := False;
  if WindowFromPoint(Mouse.CursorPos) = ScrollBox1.Handle then Result := True;
end;

function TForm3.MousePosion: Boolean;
begin
  Result := False;
  if (WindowFromPoint(Mouse.CursorPos) = Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzListBox1.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzPanel1.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzPanel2.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RxRichEdit1.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzMemo2.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzCheckBox1.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzEdit1.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzEdit2.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzEdit3.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzAnimator1.Handle)  or
    (WindowFromPoint(Mouse.CursorPos) = RzButton2.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzButton3.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzSplitter1.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzSplitter2.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = LabeledEdit1.Handle)  or
    (WindowFromPoint(Mouse.CursorPos) = RzButton4.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzButton5.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = RzPanel3.Handle) or
    (WindowFromPoint(Mouse.CursorPos) = ScrollBox1.Handle) then
    Result := True;
end;

procedure TForm3.N1Click(Sender: TObject);
begin
  RzButton5.Click;
end;

procedure TForm3.N4Click(Sender: TObject);
begin
  RzButton3.Click;
end;

procedure TForm3.PopupMenu1Popup(Sender: TObject);
begin
  N3.Visible :=RzButton3.Caption = '鎖定';
  N4.Visible := RzButton3.Caption = '鎖定';
end;

procedure TForm3.RevCustMsg(var Msg: TMessage);
var
  s:string;
  buf:TDataPack;
begin
  FillChar(buf,SizeOf(TDataPack),'');
  s:=string(PDatapack(Pointer(msg.LParam))^.Data);
  form1.RzMemo1.Lines.Add(s);
end;

procedure TForm3.RxRichEdit1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if RzTrayIcon1.Animate  then
  begin
    RzTrayIcon1.Animate := False;
    RzTrayIcon1.IconIndex := 0;
  end;
end;

procedure TForm3.RxRichEdit1URLClick(Sender: TObject; const URLText: string;
  Button: TMouseButton);
begin
  ShellExecute(Application.Handle, nil, PChar(URLText), nil, nil, SW_SHOWNORMAL);
end;

procedure TForm3.RzButton1Click(Sender: TObject);
var
  buf:TDataPack;
  Bbyte:TIdBytes;
  s,tm,bm:string;
  pt:TPoint;
  ctl:TComponent;
begin
  if Trim(RzMemo2.Text) <>'' then
  begin
    if RzListBox1.ItemIndex <> -1 then
    begin
      s:=RzListBox1.SelectedItem;
      if s= form3.RzEdit2.Text then
      begin
        RzListBox1.CustomHint.Title :='提示';
        RzListBox1.CustomHint.Description :='您不能跟本身聊天,那是欲魔行爲!';
        pt.X :=RzListBox1.Width div 2;
        pt.Y :=RzListBox1.Height div 6;
        RzListBox1.CustomHint.ImageIndex :=1;
        RzListBox1.CustomHint.HideAfter :=5000;
        RzListBox1.CustomHint.ShowHint(RzListBox1.ClientToScreen(pt));
        Exit;
      end;

      FillChar(buf, SizeOf(TDataPack), '');
      buf.Command := CltSendMessage;
      StrCopy(@buf.CltInfo.CltName, PChar(Encrystrings(form3.RzEdit2.Text)));
      StrCopy(@buf.DstInfo.CltName, PChar(Encrystrings(s)));
      tm:= RzMemo2.Text + '   (' +datetimetostr(Now)+ ')';
      StrCopy(@buf.Data, PChar(Encrystrings(tm)));
      BByte := RawToBytes(buf, SizeOf(TDataPack));
      try
        IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
        if CheckBmp(tm) then
        begin
          bm := Copy(tm,2,2);
          RxRichEdit1.Lines.Add('你對 ' +RzListBox1.SelectedItem + ' 說:');
          ctl:= FindComponent('Image'+bm);
          //ShowMessage(TImage(ctl).Name);
          if ctl <> nil then
          begin
            Clipboard.Assign(TImage(ctl).Picture);
            RxRichEdit1.PasteFromClipboard;
          end;
        end else RxRichEdit1.Lines.Add('你對 '+ RzListBox1.SelectedItem + '說: '+ tm);
        PostMessage(RxRichEdit1.Handle, WM_VSCROLL, SB_BOTTOM, 0);
        RzMemo2.Clear;
      except
//        if not  IdTCPClient1.IOHandler.Opened  then
//        begin
          ShowMessage('已與服務器斷開鏈接,消息發送不成功');
          RzListBox1.Items.Clear;
          RzEdit2.ReadOnly := False;
          RzToolButton1.Enabled := False;
          RzButton4.Enabled := False;
          RzCheckBox1.Checked := False;
//        end;

      end;
    end  else begin
      RzListBox1.CustomHint.Title :='提示';
      RzListBox1.CustomHint.Description :='請在這裏選擇一個聊天對象';
      pt.X :=RzListBox1.Width div 2;
      pt.Y :=RzListBox1.Height div 6;
      RzListBox1.CustomHint.ImageIndex :=1;
      RzListBox1.CustomHint.HideAfter :=3000;
      RzListBox1.CustomHint.ShowHint(RzListBox1.ClientToScreen(pt));
    end;
  end else begin
    RzMemo2.CustomHint.Title :='提示';
    RzMemo2.CustomHint.Description :='不能發送空消息哦';
    pt.X :=RzMemo2.Width div 2;
    pt.Y :=RzMemo2.Height div 2;
    RzMemo2.CustomHint.ImageIndex :=0;
    RzMemo2.CustomHint.HideAfter :=2000;
    RzMemo2.CustomHint.ShowHint(RzMemo2.ClientToScreen(pt));
  end;
end;

procedure TForm3.RzButton2Click(Sender: TObject);
begin
  RxRichEdit1.Clear;
end;

procedure TForm3.RzButton3Click(Sender: TObject);
var
  pt:TPoint;
  buf:TDataPack;
  Bbyte:TIdBytes;
begin
  if RzButton3.Caption = '鎖定' then
  begin
    FillChar(buf, SizeOf(TDataPack), '');
    buf.Command := CltLockSrc;
    StrCopy(@buf.CltInfo.CltName, PChar(Encrystrings(form3.RzEdit2.Text)));
    BByte := RawToBytes(buf, SizeOf(TDataPack));
    try
      try
        IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
      except
        //
      end;
    finally
      RxRichEdit1.Visible := False;
      RzMemo2.Visible := False;
      RzListBox1.Visible := False;
      RzToolButton1.Visible := False;
      RzButton4.Visible := False;
      RzButton2.Visible := False;
      RzCheckBox1.Visible := False;
      RzLabel5.Visible := False;
      RzEdit3.Visible := False;
      RzTrayIcon1.MinimizeApp;
      RzButton3.Caption :='解鎖';
      LabeledEdit1.Visible := True;
      RzLabel1.Visible := False;
      RzLabel2.Visible := False;
      RzEdit1.Visible := False;
      RzEdit2.Visible := False;
      RzPanel3.Visible := False;
      LabeledEdit1.SetFocus;
      LockStatus :=True;     //屏幕鎖定狀態
      ScrollBox1.Visible := False;
    end;
//    except
//      RzButton3.CustomHint.Title :='錯誤';
//      RzButton3.CustomHint.Description :='鎖屏失敗,請重試';
//      pt.X :=RzButton3.Width div 2;
//      pt.Y :=RzButton3.Height div 2;
//      RzButton3.CustomHint.ImageIndex :=1;
//      RzButton3.CustomHint.HideAfter :=3000;
//      RzButton3.CustomHint.ShowHint(RzButton3.ClientToScreen(pt));
//    end;
  end else begin
      if LabeledEdit1.Text = UnLockString then
      begin
        FillChar(buf, SizeOf(TDataPack), '');
        buf.Command := CltUnlockSrc;
        StrCopy(@buf.CltInfo.CltName, PChar(Encrystrings(form3.RzEdit2.Text)));
        BByte := RawToBytes(buf, SizeOf(TDataPack));
        try
          try
            IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
          except
            //
          end;
        finally
          UnLcokTimes :=0;
          RxRichEdit1.Visible := True ;
          RzMemo2.Visible := True ;
          RzListBox1.Visible := True ;
          RzToolButton1.Visible := True ;
          RzButton4.Visible := True;
          RzButton2.Visible := True ;
          RzCheckBox1.Visible := True;
          RzPanel3.Visible := True;
          RzButton3.Caption :='鎖定';
          LabeledEdit1.Text :='';
          LabeledEdit1.Visible := False;
          if not RzCheckBox1.Checked  then
          begin
            RzLabel5.Visible := True;
            RzEdit3.Visible := True;
            RzLabel1.Visible := True;
            RzLabel2.Visible := True;
            RzEdit1.Visible := True;
            RzEdit2.Visible := True;
            RzPanel3.Visible := False;
          end;
          LockStatus := False;   //屏幕鎖定狀態
//          RzButton3.CustomHint.Title :='錯誤';
//          RzButton3.CustomHint.Description :='解鎖失敗,請重試';
//          pt.X :=RzButton3.Width div 2;
//          pt.Y :=RzButton3.Height div 2;
//          RzButton3.CustomHint.ImageIndex :=1;
//          RzButton3.CustomHint.HideAfter :=3000;
//          RzButton3.CustomHint.ShowHint(RzButton3.ClientToScreen(pt));
        end;
      end else begin
        UnLcokTimes := UnLcokTimes+1;
        LabeledEdit1.Text :='';
        LabeledEdit1.CustomHint.Title :='錯誤';
        LabeledEdit1.CustomHint.Description :='解鎖密碼不正確';
        pt.X :=LabeledEdit1.Width div 2;
        pt.Y :=LabeledEdit1.Height div 2;
        LabeledEdit1.CustomHint.ImageIndex :=0;
        LabeledEdit1.CustomHint.HideAfter :=2000;
        LabeledEdit1.CustomHint.ShowHint(LabeledEdit1.ClientToScreen(pt));
        LabeledEdit1.SetFocus;
        if UnLcokTimes >=3 then
        begin
          ShowMessage('解鎖密碼嘗試3次均不正確,程序退出');
          if IdTCPClient1.Connected  then  IdTCPClient1.Disconnect;
          if Assigned(RevDataThread ) then RevDataThread.Terminate;
          Close;
        end;
      end;
  end;
end;

procedure TForm3.RzButton4Click(Sender: TObject);
var
  buf:TDataPack;
  Bbyte:TIdBytes;
  s:string;
  pt:TPoint;
begin
  if RzListBox1.ItemIndex <>-1 then
  begin
    FillChar(buf, SizeOf(TDataPack), '');
    s:=RzListBox1.SelectedItem;
    StrCopy(@buf.CltInfo.CltName, PChar(Encrystrings(form3.RzEdit2.Text)));
    StrCopy(@buf.DstInfo.CltName, PChar(Encrystrings(s)));
    buf.Command :=CltClear;
    BByte := RawToBytes(buf, SizeOf(TDataPack));
    try
      IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
      RxRichEdit1.CustomHint.Title :='提示';
      RxRichEdit1.CustomHint.Description :='您已清除本身和對方聊天記錄';
      pt.X :=RxRichEdit1.Width div 2;
      pt.Y :=RxRichEdit1.Height div 2;
      RxRichEdit1.CustomHint.ImageIndex :=1;
      RxRichEdit1.CustomHint.HideAfter :=8000;
      RxRichEdit1.CustomHint.ShowHint(RxRichEdit1.ClientToScreen(pt));
      RxRichEdit1.Clear;
    except
      ShowMessage('已與服務器斷開鏈接,清除屏幕不成功');
      RzListBox1.Items.Clear;
      RzEdit2.ReadOnly := False;
      RzToolButton1.Enabled := False;
      RzButton4.Enabled := False;
      RzCheckBox1.Checked := False;
    end;
  end else begin
      RzListBox1.CustomHint.Title :='提示';
      RzListBox1.CustomHint.Description :='請在這裏選擇一個清除屏幕對象';
      pt.X :=RzListBox1.Width div 2;
      pt.Y :=RzListBox1.Height div 6;
      RzListBox1.CustomHint.ImageIndex :=1;
      RzListBox1.CustomHint.HideAfter :=3000;
      RzListBox1.CustomHint.ShowHint(RzListBox1.ClientToScreen(pt));
  end;

end;

procedure TForm3.RzButton5Click(Sender: TObject);
begin
  Application.Terminate;
end;

procedure TForm3.RzCheckBox1Click(Sender: TObject);
var
  pt:TPoint;
begin
  IdTCPClient1.Host := RzEdit1.Text;
  if RzEdit3.Text <>'' then IdTCPClient1.Port := StrToInt(RzEdit3.Text)
  else begin
    RzEdit3.CustomHint.Title :='提示';
    RzEdit3.CustomHint.Description :='服務器端口不能爲空';
    pt.X :=RzEdit3.Width div 2;
    pt.Y :=RzEdit3.Height div 2;
    RzEdit3.CustomHint.ImageIndex :=0;
    RzEdit3.CustomHint.HideAfter :=2000;
    RzEdit3.CustomHint.ShowHint(RzEdit3.ClientToScreen(pt));
    RzCheckBox1.Checked := False;
    Exit;
  end;
  if (RzEdit2.Text ='') then
  begin
    RzEdit2.CustomHint.Title :='提示';
    RzEdit2.CustomHint.Description :='聊天暱稱不能爲空';
    pt.X :=RzEdit2.Width div 2;
    pt.Y :=RzEdit2.Height div 2;
    RzEdit2.CustomHint.ImageIndex :=0;
    RzEdit2.CustomHint.HideAfter :=2000;
    RzEdit2.CustomHint.ShowHint(RzEdit2.ClientToScreen(pt));
    RzCheckBox1.Checked := False;
    Exit;
  end;
  if Pos(' ',RzEdit2.Text)<>0 then
  begin
    RzEdit2.CustomHint.Title :='提示';
    RzEdit2.CustomHint.Description :='聊天暱稱中不能包含空格和 | 字符';
    pt.X :=RzEdit2.Width div 2;
    pt.Y :=RzEdit2.Height div 2;
    RzEdit2.CustomHint.ImageIndex :=0;
    RzEdit2.CustomHint.HideAfter :=2000;
    RzEdit2.CustomHint.ShowHint(RzEdit2.ClientToScreen(pt));
    RzCheckBox1.Checked := False;
    Exit;
  end;
  if (RzEdit1.Text ='') then
  begin
    RzEdit1.CustomHint.Title :='提示';
    RzEdit1.CustomHint.Description :='服務器地址不能爲空';
    pt.X :=RzEdit1.Width div 2;
    pt.Y :=RzEdit1.Height div 2;
    RzEdit1.CustomHint.ImageIndex :=0;
    RzEdit1.CustomHint.HideAfter :=2000;
    RzEdit1.CustomHint.ShowHint(RzEdit1.ClientToScreen(pt));
    RzCheckBox1.Checked := False;
    Exit;
  end;
  try
    if  RzCheckBox1.Checked  then
    begin
      IdTCPClient1.Connect;
      RevDataThread := TRevDataThread.Create(True);
      RevDataThread.FreeOnTerminate := True;
      RevDataThread.Start;
      RzToolButton1.Enabled := True;
      RzButton4.Enabled := True;
      RzCheckBox1.Checked := True;
      RzEdit2.ReadOnly := True;
      Timer2.Enabled := True;
      RzEdit3.Visible := False;
      RzLabel5.Visible := False;
      RzLabel1.Visible := False;
      RzLabel2.Visible := False;
      RzPanel3.Visible := True;
      RzEdit1.Visible := False;
      RzEdit2.Visible := False;
      RzAnimator1.Animate := True;
    end
    else
    begin
      IdTCPClient1.Disconnect;
      if Assigned(RevDataThread)  then  RevDataThread.Terminate;
      RzCheckBox1.Checked := False;
      RzToolButton1.Enabled :=False;
      RzButton4.Enabled := False;
      RzEdit2.ReadOnly := False;
      Timer2.Enabled := False;
      RzEdit3.Visible := True;
      RzLabel5.Visible := True;
      RzLabel1.Visible := True;
      RzLabel2.Visible := True;
      RzPanel3.Visible := False;
      RzEdit1.Visible := True;
      RzEdit2.Visible := True;
      RzAnimator1.Animate := False;
      RzAnimator1.ImageIndex :=1;
    end;
  except
    RzEdit2.ReadOnly := False;
    RzCheckBox1.Checked := False;
    RzToolButton1.Enabled :=False;
    RzButton4.Enabled := False;
    if Assigned(RevDataThread)  then  RevDataThread.Terminate;
    if IdTCPClient1.Connected then IdTCPClient1.Disconnect;
    ShowMessage('鏈接服務器失敗,請確認服務器地址是否正確');
  end;
end;

procedure TForm3.RzEdit1KeyPress(Sender: TObject; var Key: Char);
var
  tmp: string;
begin
  tmp := '0123456789.' + Char(VK_BACK) + Char(VK_DELETE);
  if Pos(Key, tmp) = 0 then Key := #0;
end;

procedure TForm3.RzEdit3KeyPress(Sender: TObject; var Key: Char);
var
  tmp: string;
begin
  tmp := '0123456789' + Char(VK_BACK) + Char(VK_DELETE);
  if Pos(Key, tmp) = 0 then Key := #0;
end;

procedure TForm3.RzListBox1DblClick(Sender: TObject);
begin
//  form1.Show;
end;

procedure TForm3.RzListBox1MouseEnter(Sender: TObject);
begin
  if RzTrayIcon1.Animate  then
  begin
    RzTrayIcon1.Animate := False;
    RzTrayIcon1.IconIndex := 0;
  end;
end;



procedure TForm3.RzMemo2KeyPress(Sender: TObject; var Key: Char);
begin
  if (Key = #13)   then
  begin
    if (((hi(GetKeyState(VK_CONTROL))) and $80) <> $80) and n2.Checked then
    begin
      Key :=#0;
      if RzToolButton1.Enabled  then RzToolButton1.Click;
    end;
  end;
end;

procedure TForm3.RzMemo2MouseEnter(Sender: TObject);
begin
  if RzTrayIcon1.Animate  then
  begin
    RzTrayIcon1.Animate := False;
    RzTrayIcon1.IconIndex := 0;
  end;
end;


procedure TForm3.RzSpinButtons1DownLeftClick(Sender: TObject);
begin
  if RzPanel3.Height > 40 then  RzPanel3.Height := (RzPanel3.Height -4) div 3;
end;

procedure TForm3.RzSpinButtons1UpRightClick(Sender: TObject);
begin
  if RzPanel3.Height <40 then RzPanel3.Height := RzPanel3.Height *3 +4;
end;

procedure TForm3.RzTrayIcon1MinimizeApp(Sender: TObject);
begin
  BoolEnable:= True;
end;

procedure TForm3.RzTrayIcon1RestoreApp(Sender: TObject);
begin
  BoolEnable:= False;
  RzTrayIcon1.Animate:= False;
  RzTrayIcon1.IconIndex := 0;
end;

procedure TForm3.SetBarHeight;
var
  AppBarData: TAPPBARDATA;
begin
  AppBarData.cbSize := SizeOf(AppBarData);
  If SHAppBarMessage(ABM_GETSTATE, AppBarData) AND (ABS_AUTOHIDE) <> 0 then
  begin
    Cur_Top := 1;
    Cur_Bottom := Screen.Height - 1;
  end
  else
  begin
    SHAppBarMessage(ABM_GETTASKBARPOS, AppBarData);
    case AppBarData.uEdge of
      ABE_TOP:
        begin
          Cur_Top := AppBarData.rc.Bottom + 1;
          Cur_Bottom := Screen.Height - 1;
        end;
      ABE_LEFT:
        begin
          Cur_Top := 1;
          Cur_Bottom := Screen.Height - 1;
        end;
      ABE_RIGHT:
        begin
          Cur_Top := 1;
          Cur_Bottom := Screen.Height - 1;
        end;
      ABE_BOTTOM:
        begin
          Cur_Top := 1;
          Cur_Bottom := Screen.Height -
            (AppBarData.rc.Bottom - AppBarData.rc.top) - 1;
        end;
    end;
  end;
end;

procedure TForm3.wmsizing(var Msg: TMessage);
begin
  inherited;
  if (akRight in FAnchors) then
  begin
    with PRect(Msg.LParam)^ do
    begin
      Left := Screen.Width - Width;
      top := Cur_Top;
      Right := Screen.Width;
      Bottom := Cur_Bottom
    end;
  end
  else if (akLeft in FAnchors) then
  begin
    with PRect(Msg.LParam)^ do
    begin
      Left := 0;
      top := Cur_Top;
      Right := Width;
      Bottom := Cur_Bottom;
    end;
  end;
end;

{ TRevDataThread }

procedure TRevDataThread.AddCltList;
var
  t,s:string;
  List:TStringList;
  OldCount,NewCount:Integer;
begin
  list:= TStringList.Create;
  OldCount := Form3.RzListBox1.Count;
  Form3.RzListBox1.Clear;
  t:= string(buf.Data);
//  count:=0;                     // dak|dkej|dinna|
//  for i:= 0 to strlen(pchar(s)) do if copy(s,i,1)='|' then count:=count+1;  //計算字符串中包含幾個分隔符 |
//  for I := 0 to Count do
//  begin
//    ss:= LeftStr(s,Pos('|',s)-1);
//  end;
  s:= Uncrystrings(t);
  s:=LeftStr(s,StrLen(PChar(s))-1);
  List.Delimiter:='|';
  List.DelimitedText:=s;
  //Form3.RzTrayIcon1.Hint := List.Text;
  Form3.RzListBox1.Items.Assign(list);
  NewCount := form3.RzListBox1.Count;
  List.Free;
  if NewCount > OldCount  then form3.RzTrayIcon1.ShowBalloonHint('提示','有用戶登陸',bhiInfo,10)
  else if NewCount < OldCount then form3.RzTrayIcon1.ShowBalloonHint('提示','有用戶下線',bhiInfo,10);
end;

procedure TRevDataThread.AddMessage;
var
  ss:string;
begin
  ss:= DecryStr(UncrypKey(string(buf.CltInfo.CltName),TKey),mkey);
  case buf.Command  of
    CltLockSrc: Form3.RxRichEdit1.Lines.Add(ss + ' 鎖定了屏幕');

    CltUnlockSrc : Form3.RxRichEdit1.Lines.Add(ss + ' 解鎖了屏幕');
  end;
  PostMessage(Form3.RxRichEdit1.Handle, WM_VSCROLL, SB_BOTTOM, 0);
end;

procedure TRevDataThread.ClearScr;
var
  pt:TPoint;
  ss:string;
begin
  Form3.RxRichEdit1.Clear;
  ss:= Uncrystrings(string(buf.CltInfo.CltName));
  Form3.RxRichEdit1.CustomHint.Title :='提示';
  Form3.RxRichEdit1.CustomHint.Description := ss+' 清除了您的聊天記錄';
  pt.X :=Form3.RxRichEdit1.Width div 2;
  pt.Y :=Form3.RxRichEdit1.Height div 2;
  Form3.RxRichEdit1.CustomHint.ImageIndex :=1;
  Form3.RxRichEdit1.CustomHint.HideAfter :=8000;
  Form3.RxRichEdit1.CustomHint.ShowHint(Form3.RxRichEdit1.ClientToScreen(pt));
  Form3.RxRichEdit1.Clear;
  Form3.RxRichEdit1.Lines.Add(ss+' 清除了您的聊天記錄');
end;

procedure TRevDataThread.CltMessageIn;
var
  s:string;
begin
  s:= Uncrystrings(string(buf.CltInfo.CltName));
  form3.RxRichEdit1.Lines.Add(s + ' 可能離開,TA的屏幕是鎖定狀態') ;
  PostMessage(Form3.RxRichEdit1.Handle, WM_VSCROLL, SB_BOTTOM, 0);
end;

procedure TRevDataThread.DoDiscnt;
begin
  form3.RzCheckBox1.Checked := False;
  Form3.IdTCPClient1.Disconnect;
  ShowMessage(Form3.RzEdit2.Text +' 已經存在,請改名從新登陸');
end;

procedure TRevDataThread.DoSrvCloseQuery;
begin
  Form3.IdTCPClient1.Disconnect;
  Form3.RzCheckBox1.Checked := False;
end;

procedure TRevDataThread.DoSrvMessage;
var
  nr,ds:string;
begin
  nr:=Uncrystrings(string(buf.Data));
  ds:= Uncrystrings(string(buf.DstInfo.CltName));
  Form3.RxRichEdit1.Lines.Add('[服務器消息]:您發送給 ['+ ds +'] 的消息: 「'+ nr +'",轉發不成功,請從新發送');
  PostMessage(Form3.RxRichEdit1.Handle, WM_VSCROLL, SB_BOTTOM, 0);
end;

procedure TRevDataThread.Execute;
var
  BByte: TIdBytes;
  Nc:string;
begin
  inherited;
  FillChar(buf, SizeOf(TDataPack), '');
  buf.Command := CltConnect;
  Nc := Encrystrings(form3.RzEdit2.Text);
  StrCopy(@buf.CltInfo.CltName, PChar(Nc));
  BByte := RawToBytes(buf, SizeOf(TDataPack));
  Form3.IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
  while (not Terminated) and (Form3.IdTCPClient1.Connected) do
  begin
    FillChar(buf, SizeOf(TDataPack), '');
    Form3.IdTCPClient1.IOHandler.ReadBytes(BByte, SizeOf(TDataPack), False);
    BytesToRaw(BByte, buf, SizeOf(TDataPack));
    case buf.Command of
      CltSendMessage:
        begin
          //SendMessage(Handle,CustMsg,CltSendMessage,Integer(PDataPack(buf)));
          Synchronize(showmsg);
          if LockStatus  then
          begin
            buf.DstInfo.CltName := buf.CltInfo.CltName;
            buf.Command := CltMessage;
            StrCopy(@buf.CltInfo.CltName, PChar(Encrystrings(form3.RzEdit2.Text)));
            BByte := RawToBytes(buf, SizeOf(TDataPack));
            Form3.IdTCPClient1.IOHandler.Write(BByte, SizeOf(TDataPack));
          end;
        end;
      CltList :                   Synchronize(AddCltList);

      CltDisconnect :             Synchronize(DoDiscnt);

      CltTimer :  ;

      CltClear :                  Synchronize(clearscr);

      CltLockSrc,CltUnlockSrc  :  Synchronize(Addmessage);

      CltMessage :                Synchronize(cltmessageIn);

      SrvMessage :                Synchronize(DoSrvMessage);

      SrvCloseQuery :             Synchronize(DoSrvCloseQuery);
    end;
  end;
end;

procedure TRevDataThread.ShowMsg;
var
  s,ss,bm:string;
  ctl:TComponent;
begin
  s:=Uncrystrings(string(buf.Data));
  ss:= Uncrystrings(string(buf.CltInfo.CltName));
  if CheckBmp(s) then
  begin
    bm := Copy(s,2,2);
    Form3.RxRichEdit1.Lines.Add(ss + ' 對你說:');
    //Clipboard.Assign(form3.Image1.Picture);
    ctl:= Form3.FindComponent('Image'+bm);
    if ctl <> nil then
    begin
      Clipboard.Assign(TImage(ctl).Picture);
      form3.RxRichEdit1.PasteFromClipboard;
    end;
  end else Form3.RxRichEdit1.Lines.Add(ss + ' 對你說:'+s );
  PostMessage(Form3.RxRichEdit1.Handle, WM_VSCROLL, SB_BOTTOM, 0);
  if BoolEnable or ((form3.Timer1.Enabled) and (not form3.MousePosion))  then
  begin
    if not Form3.RzTrayIcon1.Animate then Form3.RzTrayIcon1.Animate:=True;
  end;

end;

end.

  公共單元指針

unit Unit2;

interface

uses Windows,Messages,Classes,SysUtils,StrUtils;

 const CustMsg = WM_USER + 2110;
       CltConnect = 1;
       CltDisconnect =2;
       CltSendMessage =3;
       CltList=4;
       CltTimer =5;
       CltClear = 6;
       CltLockSrc =7;
       CltUnlockSrc = 8;
       CltMessage    = 9;
       SrvMessage  =10;
       SrvTimer =11;
       SrvCloseQuery =12;
       DataSize = 1024 *5;     //數據緩衝區大小
       UnLockString = '123456';
 type
  TCltInfo = packed record
    CltIP:array[0..14] of Char;
    CltName:array[0..255] of Char;
  end;

  TDataPack = record
    CltInfo:TCltInfo;
    DstInfo:TCltInfo;
    Command:Integer;
    Data:array[0..DataSize -1] of Char;
  end;

  PDataPack = ^TDataPack;
function Encrystrings(str:string):string;
function Uncrystrings(str:string):string;
function EncrypKey(Src: String; Key: String): string;
function UncrypKey(Src: String; Key: String): string;
function GetTMkey:string;
function CheckBmp(Str:string):Boolean;
var
  UnLcokTimes:Integer;
  LockStatus:Boolean;
implementation
  uses Unit4;

function CheckBmp(Str:string):Boolean;
begin
  Result := False;
  if Length(Str) < 4 then  Exit;
  if (LeftStr(Str,1) ='[') and (Copy(Str,4,1) = ']') then Result :=True;
end;
function Encrystrings(str:string):string;
var
  tmp:string;
begin
  tmp := EncryStr(str,MKey);
  Result := EncrypKey(tmp,TKey);
end;

function Uncrystrings(str:string):string;
var
  tmp:string;
begin
  tmp:= UncrypKey(str,TKey);
  Result := DecryStr(tmp,MKey);
end;
// 加密函數
function EncrypKey(Src: String; Key: String): string;
var
  KeyLen: integer;
  KeyPos: integer;
  offset: integer;
  dest: string;
  SrcPos: integer;
  SrcAsc: integer;
  Range: integer;
begin
  //此處省略,本身寫
end;

// 解密函數
function UncrypKey(Src: String; Key: String): string;
var
  //idx: integer;
  KeyLen: integer;
  KeyPos: integer;
  offset: integer;
  dest: string;
  SrcPos: integer;
  SrcAsc: integer;
  TmpSrcAsc: integer;
begin
 //此處省略,本身寫
end;

function GetTMkey:string;
var
  ss: string;
  n: Integer;
begin
  ss := '';
  Randomize;
  repeat
    n := Random(127);
    if n>=34 then ss := ss + char(n);
  until (Length(ss)>=12);
  Result  := ss;
end;
end.
相關文章
相關標籤/搜索